summaryrefslogblamecommitdiff
path: root/client/index.html
blob: a2ac92e1e58c8009859b15be0c6a7e52a99e8841 (plain) (tree)
1
2
3
4
5
               
                                                     
                        
                              
                














                                
                                               



                                                                       










                                                                                     


                                                                                            


                                                   



                                          











































                                                                                                                                              
            
          



                                                                  
                                                 

                                             

          

                      
    

                                       
                                          

       






























                                                                                             



                                                        




                                                          














                                                                                                                                                                     




                                           

                                    
                                       
                                                              




                                                                                



                                                          
 
           




                                                                     
 
                                                              
                            
 


                                    
                                            

                          



                                  
                              

                         
                               
 
                                   


                                                          


                        
                      





                                          
                                 
                                                    



                                 












                                                                       




                                  
                



                                    

                          
                              
                              














                                                          






                                  
                      
                                     
      

                                                  
       


                                                  

                             
                                                        
       










                                                  



                                      

                                    
                                           
                                           

                                    

                                             









                                                  

                                    
         


       
             







                                                  












                                                                                                       
                           
                               
               
                                 



                      
                        
                    
                      
                    







                                               
 





                                        




                                   
                                
                                    

                                
                              
       
     
 
                                 
                                              






                                                                           
     








                                           
                     





                                                     

                                         


                                                                     


                                


                                                                                                                       
                   
                                                             
                                                                                     
                                                                  
                                                                                    
                                                                  
                                                                                    
                                                                  

                                                                                  
                                                                                                       
       


                                       



                              
                                                           
                                                                                     
                                                                
                                                                                    
                                                                
                                                                                    
                                                                
                                                                                  


                                           


                                                                     
                                                                 
       














                                                                    
<!DOCTYPE html>
<html lang="en_US" style='background-color:#858590;'>
  <meta charset="UTF-8">
  <title>ThePixelWorld</title>
  <!-- Login -->
  <style type="text/css">
    .chat-tab{
      margin-left: 2px; 
      margin-right: 2px;
      padding-left: 3px; 
      padding-right: 3px;
      float: left; 
      color: #858590; 
      background-color: #555555;
      border-radius: 4px;
    }
    #active{
      color: lime;
    }
  </style>
  <div id="signDiv" style='text-align:center;'>
    Username: <input id="signDiv-username" type="text"></input><br>
    Password: <input id="signDiv-password" type="password"></input><br>
    <button id="signDiv-signIn">Sign In</button>
    <button id="signDiv-signUp">Sign Up</button>

    <hr>
    <div>
      <h3 style='color:red;'>Dev-Note:</h3>
      ThePixelWorld requires to load some huge map files, in case u have trouble:<br>
      Firefox dev tools network inspector truncates responses to 1MB by default.<br>
      You can change or disable the limit by navigating to <b>about:config</b><br>
      and changing <b>devtools.netmonitor.responseBodyLimit</b>.<br>
      To disable the limit, set it to <b>0</b>.
      <hr>
      <h3>News:</h3>
      tmx maps loading and rendering nearly done, beside collision system.<br>
      basic chat system (guild/party/... wip) {may also implement an api for irc usage?}<br>
      every player has a name drawn above there head now.<br>
      <h3>ToDo</h3>
      to much, and to lazy to write it down *blush*
    </div>
  </div>

  <!-- Game -->
  <div id="gameDiv" style="display:none;">
    <div id="game">
      <canvas id="ctx" width="500" height="500" tabindex="1" style="position:absolute; border:1px solid #000000;"></canvas>
      <div id="ui" tabindex="2" style="position:absolute; width:502px; height:502px; display:none;">
        <div id="ui-statusbar" style="position:absolute; border:1px solid #000000; top:50px; left:0px; width:450px; height: 40px;">
        Status Bar
        </div>
        <div id="ui-navigation" style="position:absolute; border:1px solid #000000; top:0px; left:0px; width:450px; height: 40px;">
        Navigation Bar
        </div>
        <div id="ui-menu" style="position:absolute; border:1px solid #000000; top:0px; right:0px; width:40px; height: 40px;">
        Menu
        </div>
        <div id="ui-shortcuts" style="position:absolute; border:1px solid #000000; bottom:0px; right:0px; height:450px; width: 40px;">
        Shortcut Bar
        </div>
        <div id="ui-hook" style="position:absolute; border:1px solid #000000; bottom:210px; left:0px; width:240px; height: 190px;">
        Storage/NPC(HOOKS)
        </div>
        <div id="ui-inventory" style="position:absolute; border:1px solid #000000; bottom:0px; left:0px; width:240px; height: 200px;">
        Inventory
        </div>
        <div id="ui-equip" style="position:absolute; border:1px solid #000000; bottom:0px; left:250px; width:100px; height: 200px;">
        Equip
        </div>
        <div id="ui-spells-quests" style="position:absolute; border:1px solid #000000; bottom:210px; left:250px; width:100px; height: 190px;">
        Spells/<br>Quests
        </div>
        <div id="ui-undefined" style="position:absolute; border:1px solid #000000; bottom:0px; left:360px; width:90px; height: 400px;">
        ???
        </div>
      </div>
    </div>
    <div id="chat" style="margin-top:520px;">
      <div id="chat-wrapper" style="width:500px; height:20px; overflow: hidden; white-space: nowrap;">
          <div class="chat-tab" id='active' onclick="setActiveChatTab('world', this)" >WORLD</div>
          <!-- TODO only show up on permission to use the GM tab. 
          <div class="chat-tab" onclick="setActiveChatTab('gm', this)"> GM</div> -->
          <div class="chat-tab" onclick="setActiveChatTab('guild', this)">[#] Guild (WIP)</div>
          <div class="chat-tab" onclick="setActiveChatTab('party', this)">[.] Party (WIP)</div>
        </div>
        <div id="chat-text" style="width:500px; height:100px; overflow-y:scroll;"></div>
        <form id="chat-form">
          <input id="chat-input" type="text" style="width:500px;"></input>
        </form>
      </div>
    </div>
  </div> 

   <!-- loading socket.io library -->
  <script src="https://cdn.socket.io/4.1.3/socket.io.js"></script>
  <script src="client/lib/socket.io.js"></script>
  <script src="client/consts.js"></script>
  <script src="client/tmxloader.js"></script>

  <script>
    var socket = io();
    var errno = 0;
    
    socket.on('disconnect', function(){
      errno = CONNECTION_LOST;
      alert("Connection lost..." + errno);
    });

    // Login
    var signDiv = document.getElementById("signDiv");
    var signDivUsername = document.getElementById("signDiv-username");
    var signDivPassword = document.getElementById("signDiv-password");
    var signDivSignIn = document.getElementById("signDiv-signIn");
    var signDivSignUp = document.getElementById("signDiv-signUp");

    signDivSignIn.onclick = function(){
      socket.emit('signIn', {username:signDivUsername.value, password:signDivPassword.value})
    }

    signDivSignUp.onclick = function(){
      socket.emit('signUp', {username:signDivUsername.value, password:signDivPassword.value})
    }
    socket.on('signInResponse', function(data){
      if(data.success){
        signDiv.style.display = 'none';
        gameDiv.style.display = 'inline-block';
      } 
      else
        alert("Sign in unsuccessful.");
    });
    socket.on('signUpResponse', function(data){
      if(data.success){
        alert("Sign up successful.");
      } 
      else
        alert("Sign up unsuccessful.");
    });

    // Chat
    var activeChatTab = "world"; // default tab on join.
    var chatContents = [];
    chatContents[activeChatTab] = "";

    var chatText = document.getElementById("chat-text");
    var chatInput = document.getElementById("chat-input");
    var chatForm = document.getElementById("chat-form");

    socket.on('addToChat', function(data){
      if(data.tab === "any")
        data.tab = activeChatTab;
      if (chatContents[data.tab] === undefined)
        document.getElementById("chat-wrapper").innerHTML += "<div class=\"chat-tab\" onclick=\"setActiveChatTab('" + data.tab + "', this)\">" + data.tab + "</div>";

      if(!chatContents[data.tab])
        chatContents[data.tab] = "<div title=\"" + data.ctimestamp + "\">" + data.content + "</div>"
      else
        chatContents[data.tab] += "<div title=\"" + data.ctimestamp + "\">" + data.content + "</div>"
      
      if (activeChatTab === data.tab){
        chatText.innerHTML = chatContents[activeChatTab];
        //scroll down
        chatText.scrollTop = chatText.scrollHeight;
        }
    });
    socket.on('evalAnswer', function(data){
      console.log(data);
    });
    
    chatForm.onsubmit = function(e){
        e.preventDefault();
        if (chatInput.value[0] === "*")
          socket.emit("evalServer", chatInput.value.slice(1));
        else if (chatInput.value[0] === "@" || chatInput.value[0] === "/"
          || chatInput.value[0] === "." || chatInput.value[0] === "#")
          socket.emit("command", chatInput.value);
        else if(activeChatTab !== "world")
          socket.emit("command", "/w " + activeChatTab + " " + chatInput.value);
        else
          socket.emit("sendMsgToServer", chatInput.value);
        chatInput.value = "";
    }

    // Game
    var Img = {};
    Img.player = new Image();
    Img.player.src = '/client/assets/sprites/races/human-female.png';
    Img.bullet = new Image();
    Img.bullet.src = '/client/assets/sprites/blaze.png';

    var ctx = document.getElementById("ctx").getContext("2d");
    ctx.font = '16px Arial';

    var Player = function(initPack){
      var self = {};
      self.id = initPack.id;
      self.playerName = initPack.playerName;
      self.x = initPack.x;
      self.y = initPack.y;
      self.map = initPack.map;
      self.hp = initPack.hp;
      self.hpMax = initPack.hpMax;
      self.score = initPack.score;
      self.dir = initPack.dir;
      self.shift = false;
      self.sit = false;
      self.inInventory = false;

      self.drawPlayer = function(){
        var x = self.x - Player.list[selfId].x + WIDTH/2;
        var y = self.y - Player.list[selfId].y + HEIGHT/2;

        // 'player'
        var width = 64;
        var height = 64;
        if (self.sit){
          finalWidth = width * self.dir;
          finalHeight = height * 4;
        } else {
          finalWidth = 0;
          finalHeight = height * self.dir;
        }
        ctx.drawImage(Img.player,
          finalWidth /* base sprite */, finalHeight,
          width, height,
          x-width/2, y-height/2, 
          width, height);
      }
      self.drawPlayerName = function(){
        var x = self.x - Player.list[selfId].x + WIDTH/2;
        var y = self.y - Player.list[selfId].y + HEIGHT/2;
        var hpWidth = 30 * self.hp / self.hpMax;
        // hp-bar
        ctx.fillStyle="rgba(255,0,0,0.8)";
        ctx.fillRect(x - hpWidth/2, y - 40, hpWidth, 4);
        ctx.fillStyle="rgba(75,75,75,0.8)";
        var metrics = ctx.measureText(Player.list[self.id].playerName);
        ctx.fillText(Player.list[self.id].playerName,
          x - metrics.width/2, y - 45, metrics.width, 4);
      }
      
      Player.list[self.id] = self;
      return self;
    };

    Player.list = {};
    tmxmap=null;
    
    var Bullet = function(initPack){
      var self = {};
      self.id = initPack.id;
      self.x = initPack.x;
      self.y = initPack.y;
      self.map = initPack.map;
      self.dir = initPack.dir;

      self.draw = function(){
        var width = Img.bullet.width;
        var height = Img.bullet.height;

        var x = self.x - Player.list[selfId].x + WIDTH/2;
        var y = self.y - Player.list[selfId].y + HEIGHT/2;

        ctx.drawImage(Img.bullet,
          0,0,
          width, height,
          x-width/2, y-height/2, 
          width, height);
      }

      Bullet.list[self.id] = self;
      return self;
    };

    Bullet.list = {};
    
    // init (all)
    var selfId = null;
    socket.on('init', function(data){
      
      for(var i = 0; i < data.player.length; i++){
        new Player(data.player[i]);
      }
      for(var i = 0; i < data.bullet.length; i++){
        new Bullet(data.bullet[i]);
      }
      if(data.selfId){
        selfId = data.selfId;
        tmxmap = new TMXLoader(Player.list[selfId].map);
      }
    });
    // update (diff)
    socket.on('update', function(data){
      for(var i = 0; i < data.player.length; i++){
        var pack = data.player[i];
        var p = Player.list[pack.id];
        if(p){
          if(pack.x !== undefined)
            p.x = pack.x;
          if(pack.y !== undefined)
            p.y = pack.y;
          if(pack.hp !== undefined)
            p.hp = pack.hp;
          if(pack.score !== undefined)
            p.score = pack.score;
          if(pack.dir !== undefined)
            p.dir = pack.dir;
          if(pack.playerName !== undefined)
            p.playerName = pack.playerName;
          if(pack.sit !== undefined)
            p.sit = pack.sit;
          if (pack.inInventory !== undefined)
            p.inInventory = pack.inInventory;
        }
      }
      for(var i = 0; i < data.bullet.length; i++){
        var pack = data.bullet[i];
        var b = Bullet.list[pack.id];
        if(b){
          if(pack.x !== undefined)
            b.x = pack.x;
          if(pack.y !== undefined)
            b.y = pack.y;
          if(pack.dir !== undefined)
            b.dir = pack.dir;
        }
      }
    });

    // remove
    socket.on('remove', function(data){
      for(var i = 0; i < data.player.length; i++){
        delete Player.list[data.player[i]];
      }
      for(var i = 0; i < data.bullet.length; i++){
        delete Bullet.list[data.bullet[i]];
      }
    });
    
    setActiveChatTab = function(tabName, tab){
      if (!chatContents[tabName])
        chatContents[tabName] = "";
      activeChatTab = tabName;
      chatText.innerHTML = chatContents[activeChatTab];
      Array.from(document.getElementsByClassName("chat-tab")).forEach(function(element, index, array) {
       element.setAttribute("id", "");
      })
      tab.setAttribute("id", "active");
      chatText.scrollTop = chatText.scrollHeight;
    }
    
    setInterval(function(){
      if(!selfId || errno != 0)
        return;
      ctx.clearRect(0,0,500,500);
      drawMapGround();
      drawGFXGround();
      drawEntities();
      drawMapOver();
      drawPlayerNames();
      drawGFXOver();
      drawInventory();
      //drawScore();
    }, 1000/25);

    var drawMapGround = function(){
      var x = WIDTH/2 - Player.list[selfId].x;
      var y = HEIGHT/2 - Player.list[selfId].y;

      tmxmap.drawLayer("ground",x,y);
    }

    var drawPlayerNames = function(){
      for(var i in Player.list){
        Player.list[i].drawPlayerName();
      }
    }

    var drawGFXGround = function(){

    }

    var drawEntities = function(){
      for(var i in Player.list){
        Player.list[i].drawPlayer();
      }
      for(var i in Bullet.list){
        Bullet.list[i].draw();
      }
    }

    var drawMapOver = function(){
      var x = WIDTH/2 - Player.list[selfId].x;
      var y = HEIGHT/2 - Player.list[selfId].y;
      tmxmap.drawLayer("fringe",x,y); // needs to get rendered on last pos.
      tmxmap.drawLayer("over",x,y);
    }

    var drawGFXOver = function(){

    }

    var drawInventory = function(){
      if(Player.list[selfId].inInventory) {
        ui.style.display = 'inline-block';
      }
      else {
        ui.style.display = 'none';
      }
    }
    // TODO Collision

    var drawScore = function(){
      ctx.fillStyle = 'green';
      ctx.fillText(Player.list[selfId].score, 0, 30);
    }

    document.onkeydown = function(event){
      //console.log(event.keyCode);
      if (document.activeElement === document.getElementById('ui') ||
        document.activeElement === document.getElementById('game') ||
        document.activeElement === document.getElementById('ctx')){
        // shift
        if(event.keyCode === 16)
          self.shift = true;
        // inventory (i)
        if(event.keyCode === 73)
          socket.emit('keyPress',{inputId: 'inInventory', state: !Player.list[selfId].inInventory, shift: self.shift});
        // movement
        if(event.keyCode === 68 || event.keyCode === 39) // d
          socket.emit('keyPress',{inputId: 'right', state: true, shift: self.shift});
        else if(event.keyCode === 65 || event.keyCode === 37) // a
          socket.emit('keyPress',{inputId: 'left', state: true, shift: self.shift});
        else if(event.keyCode === 83 || event.keyCode === 40) // s
          socket.emit('keyPress',{inputId: 'down', state: true, shift: self.shift});
        else if(event.keyCode === 87 || event.keyCode === 38) // w
          socket.emit('keyPress',{inputId: 'up', state: true, shift: self.shift});
        else if(event.keyCode === 88)
          socket.emit('keyPress',{inputId: 'sit', state: !Player.list[selfId].sit, shift: self.shift});
      }
    }

    document.onkeyup = function(event){
      // shift
      if(event.keyCode === 16)
        self.shift = false;
      // movement
      if(event.keyCode === 68 || event.keyCode === 39) // d
        socket.emit('keyPress', {inputId: 'right', state: false, shift: self.shift});
      else if(event.keyCode === 65 || event.keyCode === 37) // a
        socket.emit('keyPress', {inputId: 'left', state: false, shift: self.shift});
      else if(event.keyCode === 83 || event.keyCode === 40) // s
        socket.emit('keyPress', {inputId: 'down', state: false, shift: self.shift});
      else if(event.keyCode === 87 || event.keyCode === 38) // w
        socket.emit('keyPress', {inputId: 'up', state: false, shift: self.shift});
    }

    document.onmousedown = function(event){
      if (document.activeElement === document.getElementById('ui') ||
        document.activeElement === document.getElementById('game') ||
        document.activeElement === document.getElementById('ctx')){
        socket.emit('keyPress',{inputId: 'attack', state: true});
      }
    }
    
    document.onmouseup = function(event){
        socket.emit('keyPress',{inputId: 'attack', state: false});
    }
    
    document.onmousemove = function(event){
      var x = -250 + event.clientX - 8;
      var y = -250 + event.clientY - 8;
      var angle = Math.atan2(y, x) / Math.PI * 180;
      socket.emit('keyPress',{inputId: 'mouseAngle', state: angle});
    }

  </script>
</html>