Advertisement
Guest User

app.js

a guest
Nov 19th, 2017
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var io = require('socket.io-client');
  2. var Canvas = require('./canvas');
  3. var global = require('./global');
  4. var color = require('./color');
  5.  
  6. var playerNameInput = document.getElementById('playerNameInput');
  7. var playerKeyInput = document.getElementById('playerKeyInput');
  8. var socket;
  9. var reason;
  10.  
  11. var angleDifference = function(sourceA, targetA) {
  12.     let mod = function(a, n) {
  13.         return (a % n + n) % n;
  14.     };
  15.     let a = targetA - sourceA;
  16.     return mod(a + Math.PI, 2*Math.PI) - Math.PI;
  17. };
  18.  
  19. if ( /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent) ) {
  20.     global.mobile = true;
  21. }
  22.  
  23. function strEncodeUTF16(str) {
  24.     var buf = new ArrayBuffer(str.length*2);
  25.     var bufView = new Uint16Array(buf);
  26.     for (var i=0, strLen=str.length; i < strLen; i++) {
  27.         bufView[i] = str.charCodeAt(i);
  28.     }
  29.     return bufView;
  30. }
  31.  
  32. function strDecodeUTF16(arr) {
  33.     let buf;
  34.     if (arr.buffer == null) {
  35.         let len = 0;
  36.         for (let i=0; arr[i]!=null; i++) { len++; }
  37.         buf = new Uint16Array(new ArrayBuffer(len*2));
  38.         for (let i=0; i<len; i++) {
  39.             buf[i] = arr[i];
  40.         }
  41.     } else {
  42.         buf = new Uint16Array(arr);
  43.     }
  44.     return String.fromCharCode.apply(null, buf);
  45. }
  46.  
  47. function submitToLocalStorage(name) {
  48.     localStorage.setItem(name, document.getElementById(name).value);
  49.     console.log(localStorage.getItem(name));
  50.     return false;
  51. }
  52.  
  53. function retrieveFromLocalStorage(name) {
  54.     document.getElementById(name).value = localStorage.getItem(name);
  55.     return false;
  56. }
  57.  
  58. function startGame(type) {
  59.     submitToLocalStorage('playerNameInput');
  60.     submitToLocalStorage('playerKeyInput');
  61.  
  62.     global.playerName = strEncodeUTF16(playerNameInput.value);
  63.     global.playerKey = playerKeyInput.value.replace(/(<([^>]+)>)/ig, '').substring(0, 64);
  64.     global.playerType = type;
  65.  
  66.     global.screenWidth = window.innerWidth;
  67.     global.screenHeight = window.innerHeight;
  68.  
  69.     document.getElementById('startMenuWrapper').style.maxHeight = '0px';
  70.     document.getElementById('gameAreaWrapper').style.opacity = 1;
  71.     if (!socket) {
  72.         socket = io({query:"type=" + type});
  73.         setupSocket(socket);
  74.     }
  75.     if (!global.animLoopHandle){
  76.         animloop();
  77.     }
  78.     socket.emit('spawn', global.playerKey);
  79.     window.canvas.socket = socket;
  80.     global.socket = socket;
  81. }
  82.  
  83. window.onload = function() { //Change the screen when we start play
  84.     var btn = document.getElementById('startButton');
  85.     retrieveFromLocalStorage('playerNameInput');
  86.     retrieveFromLocalStorage('playerKeyInput');
  87.  
  88.     btn.onclick = function () {
  89.         startGame('player');
  90.     };
  91.  
  92.     playerNameInput.addEventListener('keypress', function (e) {
  93.         var key = e.which || e.keyCode;
  94.         if (key === global.KEY_ENTER) {
  95.             startGame('player');
  96.         }
  97.     });
  98. };
  99.  
  100. var config = {
  101.         graphical: {
  102.             screenshotMode: false,
  103.         },
  104.     },  
  105.     player = { //Set up the player
  106.         id: -1,
  107.         x: global.screenWidth / 2,
  108.         y: global.screenHeight / 2,
  109.         vx: 0,
  110.         vy: 0,
  111.         renderx: global.screenWidth / 2,
  112.         rendery: global.screenHeight / 2,
  113.         renderv: 1,
  114.         slip: 0,
  115.         view: 1,
  116.         time: 0,
  117.         screenWidth: global.screenWidth,
  118.         screenHeight: global.screenHeight,
  119.         target: {x: global.screenWidth / 2, y: global.screenHeight / 2}
  120.     },
  121.     entities = [],
  122.     users = [],
  123.     gui = {
  124.         skills: {
  125.             typeData:[],
  126.             points: 0,
  127.         },
  128.         upgrades: [],
  129.         score: 0,
  130.         progress: 0,
  131.         level: 0,
  132.         type: "Unknown Entity"
  133.     },
  134.     minimap = [],
  135.     leaderboard = [],
  136.     leaderboardScore = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
  137.     upgradeSpin = 0,
  138.     messages = [],
  139.     mockups = [],
  140.     messageFade = 0,
  141.     newMessage = 0,
  142.     metrics = {
  143.         latency: 0,
  144.         lag: 0,
  145.         rendertime: 0,
  146.         updatetime: 0,
  147.         lastlag: 0,
  148.         lastrender: 0,
  149.         rendergap: 0,
  150.         lastuplink: 0,
  151.     },
  152.     lastPing = 0,
  153.     renderTimes = 0,
  154.     updateTimes = 0,
  155.     target = {x: player.x, y: player.y},
  156.     roomSetup = [ [ 'norm'] ];
  157.  
  158.  
  159.  
  160. global.target = target;
  161. global.player = player;
  162. global.canUpgrade = false;
  163. global.canSkill = false;
  164. global.messages = '';
  165. global.time = 0;
  166. window.canvas = new Canvas();
  167. var c = window.canvas.cv,
  168.     ctx = c.getContext('2d'),
  169.     c2 = document.createElement('canvas'),
  170.     ctx2 = c2.getContext('2d');
  171.     ctx2.imageSmoothingEnabled = false;
  172.  
  173. function convertRawData(data) {
  174.     function process(i) {
  175.         return {
  176.             id:         i[0][0],
  177.             index:      i[0][1],
  178.             x:          i[0][2],
  179.             y:          i[0][3],
  180.             vx:         i[0][4],
  181.             vy:         i[0][5],
  182.             size:       i[0][6],
  183.             realSize:   i[0][7],
  184.             fade:       i[0][8],
  185.             color:      i[0][9],
  186.             blend: {
  187.                 color:  i[0][10],
  188.                 amount: i[0][11],
  189.             },
  190.             health:     i[0][12],
  191.             shield:     i[0][13],
  192.             coherence:  i[0][14],
  193.             facing:     i[0][15],
  194.             shape:      i[0][16],
  195.             name:       i[0][17],
  196.             score:      i[0][18],
  197.             twiggle:    i[0][19],
  198.             layer:      i[0][20],
  199.             vfacing:    i[0][21],
  200.             nameplate:  i[0][22],
  201.             guns:       i[1],
  202.             turrets: i[2].map((t) => { return process(t); }),
  203.         };
  204.     }
  205.     return data.map((datum) => {
  206.         datum = process(datum);
  207.         let e = entities.find(x => x.id === datum.id);
  208.         if (e != null) {
  209.             e.render.lastx = e.x;
  210.             e.render.lasty = e.y;
  211.             e.render.lastvx = e.vx;
  212.             e.render.lastvy = e.vy;
  213.             e.render.lastf = e.facing;
  214.             let save = e.render;
  215.             e = datum;
  216.             e.render = save;
  217.         } else {
  218.             e = datum;
  219.             e.render = {
  220.                 x: datum.x,
  221.                 y: datum.y,
  222.                 lastx: datum.x,
  223.                 lasty: datum.y,
  224.                 lastvx: datum.vx,
  225.                 lastvy: datum.vy,
  226.                 lastf: datum.facing,
  227.                 f: datum.facing,
  228.                 h: datum.health,
  229.                 s: datum.shield,
  230.                 slip: 0,
  231.             };
  232.         }
  233.         return e;
  234.     });
  235. }
  236.  
  237. function getEntityImageFromMockup(index, color = mockups[index].color) {
  238.     let mockup = mockups[index];
  239.     return {
  240.         time: 0,
  241.         index: index,
  242.         x: mockup.x,
  243.         y: mockup.y,
  244.         vx: 0,
  245.         vy: 0,
  246.         size: mockup.size,
  247.         realSize: mockup.realSize,
  248.         fade: 1,
  249.         color: color,
  250.         blend: {
  251.             color: '#FFFFFF',
  252.             amount: 0,
  253.         },
  254.         health: 1,
  255.         shield: 0,
  256.         coherence: 1,
  257.         facing: mockup.facing,
  258.         shape: mockup.shape,
  259.         name: mockup.name,
  260.         score: 0,
  261.         tiggle: 0,
  262.         layer: mockup.layer,
  263.         guns: mockup.guns.map(() => { return 0; }),
  264.         turrets: mockup.turrets.map((t) => {
  265.             let o = getEntityImageFromMockup(t.type);
  266.             o.realSize = o.realSize / o.size * mockup.size * t.sizeFactor;
  267.             o.size = mockup.size * t.sizeFactor;
  268.             o.x += mockup.x + mockup.size * t.offset * Math.cos(t.direction + t.angle);
  269.             o.y += mockup.y + mockup.size * t.offset * Math.sin(t.direction + t.angle);
  270.             o.facing = t.direction + t.angle;
  271.             o.layer = t.layerOverride;
  272.             return o;
  273.         }),
  274.     };
  275. }
  276.  
  277. function setupSocket(socket) { // Socket stuff.x`
  278.     socket.on('disconnect', function(m) { // System disconnection
  279.         global.disconnected = true;
  280.         global.messages = m;
  281.         socket.close();
  282.     });    
  283.     socket.on('kick', function(m) { // Manual disconnection
  284.         if (global.gameStart) global.disconnected = true;
  285.         global.messages = m;
  286.     });
  287.     socket.on('welcome', function(playerSettings) { // Handle connection.
  288.         player = playerSettings;
  289.         player.name = global.playerName;
  290.         player.screenWidth = global.screenWidth;
  291.         player.screenHeight = global.screenHeight;
  292.         player.vx = 0;
  293.         player.vy = 0;
  294.         player.renderx = player.x;
  295.         player.rendery = player.y;
  296.         player.lastx = player.x;
  297.         player.lasty = player.y;
  298.         player.lastvx = 0;
  299.         player.lastvy = 0;
  300.         player.target = window.canvas.target;
  301.         global.player = player;
  302.         socket.emit('gotit', player); //Say hi back to mama server
  303.         global.gameStart = true;
  304.         c.focus();
  305.     });    
  306.     socket.on('gameSetup', function(data, mockupData, setup) { // Initalization call
  307.         global.gameWidth = data.gameWidth;
  308.         global.gameHeight = data.gameHeight;
  309.         resize();
  310.         mockups = mockupData;
  311.         roomSetup = setup;
  312.     });        
  313.     socket.on('uplink', function(camera, entityList, newGui) { // Handle updates.
  314.         var ratio = Math.max(global.screenWidth / player.renderv, global.screenHeight / player.renderv / 9 * 16);
  315.         socket.emit('downlink', { // Send a heartbeat back to the server  
  316.             x: window.canvas.target.x / ratio,
  317.             y: window.canvas.target.y / ratio,
  318.         }, Math.max(player.time, camera.time));
  319.         if (camera.time > player.time || player.time == null) { // Don't accept out-of-date information.
  320.             metrics.lastuplink = Date.now();
  321.             metrics.rendergap = metrics.lastuplink - player.time;
  322.             player.time = camera.time;
  323.             player.lastx = player.x;
  324.             player.lasty = player.y;
  325.             player.x = camera.x;
  326.             player.y = camera.y;
  327.             player.lastvx = player.vx;
  328.             player.lastvy = player.vy;
  329.             player.vx = camera.vx;
  330.             player.vy = camera.vy;
  331.             if (isNaN(player.renderx)) { player.renderx = player.x; }
  332.             if (isNaN(player.rendery)) { player.rendery = player.y; }
  333.             player.view = camera.view;
  334.             if (isNaN(player.renderv) || player.renderv === 0) { player.renderv = 2000; }
  335.             entities = convertRawData(entityList);
  336.             gui = newGui;
  337.             metrics.lastlag = metrics.lag;
  338.         } else { console.log("Old data!"); }
  339.         updateTimes++; // metrics
  340.     });
  341.     socket.on('minimapUpdate', function(newMap, newLeaderboard) { // Update the minimap
  342.         minimap = newMap;
  343.         leaderboard = newLeaderboard;
  344.     });
  345.     socket.on('RIP', function() { // Death
  346.         global.died = true;
  347.         /*if (global.animLoopHandle) {
  348.             window.cancelAnimationFrame(global.animLoopHandle);
  349.         }*/
  350.     });
  351.     socket.on('message', function(message) { // Death
  352.         messages.push({
  353.             text: message,
  354.             status: 2,
  355.             alpha: 0,
  356.             time: Date.now(),
  357.         });
  358.     });
  359.     socket.on('pongcheck', function(t) {
  360.         console.log('!Pong!');
  361.         metrics.latency = global.time - t;
  362.     });
  363. }
  364.  
  365. function getColor(colorNumber) {
  366.     switch (colorNumber) {
  367.         case 0: return color.teal;
  368.         case 1: return color.lgreen;
  369.         case 2: return color.orange;
  370.         case 3: return color.yellow;
  371.         case 4: return color.lavender;
  372.         case 5: return color.pink;
  373.         case 6: return color.vlgrey;
  374.         case 7: return color.lgrey;
  375.         case 8: return color.guiwhite;
  376.         case 9: return color.black;
  377.         case 10: return color.blue;
  378.         case 11: return color.green;
  379.         case 12: return color.red;
  380.         case 13: return color.gold;
  381.         case 14: return color.purple;
  382.         case 15: return color.magenta;
  383.         case 16: return color.grey;
  384.         case 17: return color.dgrey;
  385.         case 18: return color.white;
  386.         case 19: return color.guiblack;
  387.        
  388.         default: return '#FF0000';
  389.     }
  390. }
  391.  
  392. function getColorDark(colorNumber) {
  393.     return color.black;
  394. }
  395.  
  396. function getZoneColor(cell, real) {
  397.     switch (cell) {
  398.     case 'bas1': return color.blue;
  399.     case 'bas2': return color.pink;
  400.     case 'bas3': return color.red;
  401.     case 'bas4': return color.green;
  402.     case 'nest': return (real) ? color.purple : color.lavender;    
  403.     default: return (real) ? color.white : color.lgrey;
  404.     }
  405. }
  406.  
  407. function mixColors(color_2, color_1, weight = 0.5) {
  408.  
  409.     /** https://gist.github.com/jedfoster/7939513 **/
  410.  
  411.     function d2h(d) { return d.toString(16); }  // convert a decimal value to hex
  412.     function h2d(h) { return parseInt(h, 16); } // convert a hex value to decimal
  413.     if (weight === 1) return color_1;
  414.     if (weight === 0) return color_2;
  415.     var color = "#";  
  416.     for(var i = 1; i <= 6; i += 2) { // loop through each of the 3 hex pairs—red, green, and blue, skip the '#'
  417.         var v1 = h2d(color_1.substr(i, 2)), // extract the current pairs
  418.             v2 = h2d(color_2.substr(i, 2)),            
  419.             // combine the current pairs from each source color, according to the specified weight
  420.             val = d2h(Math.floor(v2 + (v1 - v2) * weight));
  421.    
  422.         while(val.length < 2) { val = '0' + val; } // prepend a '0' if val results in a single digit        
  423.         color += val; // concatenate val to our new color string
  424.     }      
  425.     return color; // PROFIT!
  426. }  
  427.  
  428. function clearScreen(clearColor, alpha) {
  429.     ctx.fillStyle = clearColor;
  430.     ctx.globalAlpha = alpha;    
  431.     ctx.fillRect(0, 0, global.screenWidth, global.screenHeight);
  432.     ctx.globalAlpha = 1;    
  433. }
  434.  
  435. function drawText(text, x, y, size, fillColor, angle = 0){
  436.     ctx.lineWidth = Math.max(3, size/5);  
  437.     if (angle) {
  438.         ctx.save();
  439.         ctx.translate(x, y);
  440.         ctx.rotate(-angle * Math.PI / 180);
  441.         ctx.strokeStyle = color.black;
  442.         ctx.fillStyle = fillColor;
  443.         ctx.font = 'bold ' + size + 'px Ubuntu';
  444.         ctx.strokeText(text, x, y);
  445.         ctx.fillText(text, x, y);
  446.         ctx.restore();
  447.     } else {
  448.         ctx.strokeStyle = color.black;
  449.         ctx.fillStyle = fillColor;
  450.         ctx.font = 'bold ' + size + 'px Ubuntu';
  451.         ctx.strokeText(text, x, y);
  452.         ctx.fillText(text, x, y);
  453.     }
  454. }
  455.  
  456. function measureText(text, size) {
  457.     ctx.font = 'bold ' + size + 'px Ubuntu';
  458.     return ctx.measureText(text).width;
  459. }
  460.  
  461. function drawCircle(context, centerX, centerY, radius, sides, angle = 0, fill = true) {
  462.     let theta;
  463.     let x = 0;
  464.     let y = 0;
  465.     angle += (sides % 2) ? 0 : Math.PI / sides;
  466.  
  467.     context.beginPath();
  468.  
  469.     if (sides < 0) {
  470.         let dip = 1 - ( 6 / sides / sides);
  471.         sides = -2 * sides;
  472.         let appliedDip = 1;
  473.         context.lineJoin = 'miter';
  474.  
  475.         for (let i=0; i < sides; i++) {
  476.             theta = (i / sides) * 2 * Math.PI;
  477.             x = centerX + radius * appliedDip * Math.cos(theta + angle);
  478.             y = centerY + radius * appliedDip * Math.sin(theta + angle);
  479.             if (appliedDip === 1) { appliedDip = dip; } else { appliedDip = 1; }
  480.             context.lineTo(x, y);
  481.         }
  482.     } else {
  483.         for (let i=0; i < sides; i++) {
  484.             theta = (i / sides) * 2 * Math.PI;
  485.             x = centerX + radius * Math.cos(theta + angle);
  486.             y = centerY + radius * Math.sin(theta + angle);
  487.             context.lineTo(x, y);
  488.         }
  489.     }
  490.  
  491.     context.closePath();
  492.     context.stroke();
  493.     context.lineJoin = 'round';
  494.     if (fill) { context.fill(); }
  495. }
  496.  
  497. function drawTrapezoid(context, x, y, length, height, aspect, angle) {
  498.     let h = [];
  499.     h = (aspect > 0) ?
  500.         [ height * aspect, height ] :
  501.         [ height, -height * aspect ];
  502.     let r = [
  503.         Math.atan2(h[0], length),
  504.         Math.atan2(h[1], length)
  505.     ];
  506.     let l = [
  507.         Math.sqrt(length * length + h[0] * h[0]),
  508.         Math.sqrt(length * length + h[1] * h[1])
  509.     ];
  510.  
  511.     context.beginPath();
  512.         context.lineTo(x + l[0] * Math.cos(angle + r[0]),           y + l[0] * Math.sin(angle + r[0]));
  513.         context.lineTo(x + l[1] * Math.cos(angle + Math.PI - r[1]), y + l[1] * Math.sin(angle + Math.PI - r[1]));
  514.         context.lineTo(x + l[1] * Math.cos(angle + Math.PI + r[1]), y + l[1] * Math.sin(angle + Math.PI + r[1]));
  515.         context.lineTo(x + l[0] * Math.cos(angle - r[0]),           y + l[0] * Math.sin(angle - r[0]));    
  516.     context.closePath();
  517.     context.stroke();
  518.     context.fill();
  519. }
  520.  
  521. function drawGuiRect(x, y, length, height, stroke = false) {
  522.     switch (stroke) {
  523.     case true: ctx.strokeRect(Math.round(x) + 0.5, Math.round(y) + 0.5, Math.round(length), Math.round(height)); break;
  524.     case false:  ctx.fillRect(Math.round(x) + 0.5, Math.round(y) + 0.5, Math.round(length), Math.round(height)); break;
  525.     }
  526. }
  527.  
  528. function drawGuiLine(x1, y1, x2, y2) {
  529.     ctx.beginPath();
  530.         ctx.lineTo(Math.round(x1) + 0.5, Math.round(y1) + 0.5);
  531.         ctx.lineTo(Math.round(x2) + 0.5, Math.round(y2) + 0.5);
  532.     ctx.closePath();
  533.     ctx.stroke();
  534. }
  535.  
  536. function drawEntity(x, y, instance, ratio, scale=1, rot=0, turretsObeyRot=1, assignedContext=false) {
  537.     let drawSize = scale * ratio * instance.size * (1 + 0.5 * (1 - instance.fade));
  538.     let m = mockups[instance.index];
  539.  
  540.     context = (assignedContext) ? assignedContext : ctx;
  541.     let xx = x, yy = y;
  542.     if (assignedContext != ctx2 && instance.fade !== 1) {
  543.         context = ctx2;
  544.         context.canvas.width = drawSize * m.position.axis + ratio * 10;
  545.         context.canvas.height = drawSize * m.position.axis + ratio * 10;
  546.         xx = context.canvas.width / 2 - drawSize * m.position.axis * m.position.middle.x * Math.cos(rot) / 4;
  547.         yy = context.canvas.height / 2 - drawSize * m.position.axis * m.position.middle.x * Math.sin(rot) / 4;
  548.     }
  549.     // Draw guns  
  550.     context.lineWidth = Math.max(2, ratio*4);
  551.     context.fillStyle = mixColors(color.grey, instance.blend.color, instance.blend.amount);
  552.     context.strokeStyle = color.black;
  553.     if (instance.guns.length === m.guns.length) {
  554.         for (let i=0; i<m.guns.length; i++) {
  555.             let g = m.guns[i],
  556.                 position = instance.guns[i],
  557.                 gx =
  558.                     g.offset * Math.cos(g.direction + g.angle + rot) +
  559.                     (g.length - position) / 2 * Math.cos(g.angle + rot),
  560.                 gy =
  561.                     g.offset * Math.sin(g.direction + g.angle + rot) +
  562.                     (g.length - position) / 2 * Math.sin(g.angle + rot);                
  563.             drawTrapezoid(
  564.                 context,
  565.                 xx + drawSize * gx,
  566.                 yy + drawSize * gy,
  567.                 drawSize * g.length / 2,
  568.                 drawSize * g.width / 2,
  569.                 g.aspect,
  570.                 g.angle + rot
  571.             );
  572.         }  
  573.     } else { throw ("Mismatch gun number with mockup."); }
  574.     // Draw turrets beneath us
  575.     instance.turrets.forEach((t) => {
  576.         if (t.layer === 0) {
  577.             if (turretsObeyRot*rot) {
  578.                 let ang = Math.atan2(t.y, t.x) + turretsObeyRot*rot,
  579.                     len = Math.sqrt(t.y * t.y + t.x * t.x) * drawSize / instance.size;
  580.                 drawEntity(xx + len * Math.cos(ang), yy + len * Math.sin(ang), t, ratio, scale, turretsObeyRot*rot + t.facing, turretsObeyRot, context);
  581.             } else {
  582.                 drawEntity(xx + scale * ratio * t.x, yy + scale * ratio * t.y, t, ratio, scale, turretsObeyRot*rot + t.facing, turretsObeyRot, context);
  583.             }
  584.         }
  585.     });
  586.     // Draw body
  587.     let sides = (instance.shape) ? instance.shape : 25; // Default sides for a circle shall be 30.
  588.     context.fillStyle = mixColors(getColor(instance.color), instance.blend.color, instance.blend.amount);
  589.     context.strokeStyle = getColorDark(instance.color);
  590.     drawCircle(context, xx, yy, drawSize / instance.size * instance.realSize, sides, rot);    
  591.     // Draw turrets above us
  592.     instance.turrets.forEach((t) => {
  593.         if (t.layer === 1) {
  594.             if (turretsObeyRot*rot) {
  595.                 let ang = Math.atan2(t.y, t.x) + turretsObeyRot*rot,
  596.                     len = Math.sqrt(t.y * t.y + t.x * t.x) * scale*ratio;
  597.                 drawEntity(xx + len * Math.cos(ang), yy + len * Math.sin(ang), t, ratio, scale, turretsObeyRot*rot + t.facing, turretsObeyRot, context);
  598.             } else {
  599.                 drawEntity(xx + scale*ratio * t.x, yy + scale*ratio * t.y, t, ratio, scale, turretsObeyRot*rot + t.facing, turretsObeyRot, context);
  600.             }
  601.         }
  602.     });
  603.     if (assignedContext == false && context != ctx) {
  604.         ctx.globalAlpha = instance.fade;
  605.         ctx.imageSmoothingEnabled = false;
  606.         //ctx.globalCompositeOperation = "overlay";
  607.         ctx.drawImage(context.canvas, x - xx, y - yy);
  608.         ctx.globalAlpha = 1;
  609.         ctx.imageSmoothingEnabled = true;
  610.         //ctx.globalCompositeOperation = "source-over";
  611.     }
  612. }
  613.  
  614. function handleLargeNumber(a, cullZeroes = false) {
  615.     if (cullZeroes && a == 0) {
  616.         return '';
  617.     }
  618.  
  619.     if (a < Math.pow(10, 3)) {
  620.         return '' + a.toFixed(0);
  621.     }
  622.    
  623.     if (a < Math.pow(10, 6)) {
  624.         return (a / Math.pow(10, 3)).toFixed(2) + "k";
  625.     }
  626.    
  627.     if (a < Math.pow(10, 9)) {
  628.         return (a / Math.pow(10, 6)).toFixed(2) + "m";
  629.     }
  630.    
  631.     if (a < Math.pow(10, 12)) {
  632.         return (a / Math.pow(10, 9)).toFixed(2) + "b";
  633.     }
  634.    
  635.     if (a < Math.pow(10, 15)) {
  636.         return (a / Math.pow(10, 12)).toFixed(2) + "t";
  637.     }
  638.    
  639.     return (a / Math.pow(10, 15)).toFixed(2) + "q";
  640.    
  641. }
  642.  
  643. function drawBar(x1, x2, y, width, color) {
  644.     ctx.beginPath();
  645.         ctx.lineTo(x1, y);
  646.         ctx.lineTo(x2, y);
  647.         ctx.lineWidth = width;
  648.         ctx.strokeStyle = color;
  649.     ctx.closePath();
  650.     ctx.stroke();
  651. }
  652.  
  653. function drawHealth(x, y, instance, ratio) {
  654.     // Draw health bar
  655.     let alpha = instance.fade * instance.fade;
  656.     ctx.globalAlpha = alpha;
  657.     let size = instance.size * ratio;
  658.     let realSize = instance.realSize * ratio;
  659.    
  660.     if (instance.health < 0.99 || instance.shield < 0.99) {
  661.         let yy = y + 1.1*realSize + 15;
  662.         drawBar(x-size, x+size, yy, 6, color.black);
  663.         drawBar(x-size, x-size+2*size*instance.health, yy, 3, color.lgreen);
  664.         ctx.globalAlpha = instance.coherence*0.9;
  665.         drawBar(x-size, x-size+2*size*instance.shield, yy, 3, color.teal);
  666.     }
  667.     ctx.globalAlpha = 1;
  668.  
  669.     // Draw label
  670.     if (instance.nameplate) {
  671.         ctx.lineWidth = 3;
  672.         ctx.textAlign = 'center';      
  673.         drawText(strDecodeUTF16(instance.name), x, y - realSize - 24, 16, color.guiwhite);
  674.         drawText(handleLargeNumber(instance.score, true), x, y - realSize - 10, 8, color.guiwhite);
  675.     }
  676.  
  677. }
  678.  
  679. window.requestAnimFrame = (function() {
  680.     return  window.requestAnimationFrame       ||
  681.             window.webkitRequestAnimationFrame ||
  682.             window.mozRequestAnimationFrame    ||
  683.             window.msRequestAnimationFrame     ||
  684.             function( callback ) {
  685.                 //window.setTimeout(callback, 1000 / 60);
  686.             };
  687. })();
  688.  
  689. window.cancelAnimFrame = (function(handle) {
  690.     return  window.cancelAnimationFrame     ||
  691.             window.mozCancelAnimationFrame;
  692. })();
  693.  
  694. function gameDraw(ratio) { // Draws the game environment and the gui above that
  695.     ctx.lineCap = 'round';
  696.     ctx.lineJoin = 'round';
  697.     renderGap = (global.time - metrics.lastrender);
  698.     renderTimes++;            
  699.     try {
  700.         interpolateMotion = (v1, v2, t) => {
  701.             let tt = 1 + t / metrics.rendergap;
  702.             return (Math.abs(v1 + v2) < 0.001) ? tt : tt * (v1 + 0.5 * tt * (v2 - v1)) / (v1 + 0.5 * (v2 - v1));
  703.         };
  704.  
  705.         extrapolateMotion = (v1, v2, t) => {
  706.             let wubt = t, // (t <= 1000) ? t : 10 * Math.log(1 + (t - 1000) / 10) + 1000,
  707.                 tt = 30 * wubt / 1000,
  708.                 drop = Math.min(1, Math.max(0, 1.5 - t / 1000));
  709.             return (v2 + wubt / metrics.rendergap * (v2 - v1)) * tt * drop;
  710.         };
  711.  
  712.         let t = gui.fps * (global.time - player.time - Math.max(metrics.rendergap, 50));
  713.  
  714.         { // Move the camera
  715.             player.renderx = (t >= 0) ?
  716.                 player.x + extrapolateMotion(player.lastvx, player.vx, t) :
  717.                 player.lastx + (player.x - player.lastx) * interpolateMotion(player.lastvx, player.vx, t);
  718.             player.rendery = (t >= 0) ?
  719.                 player.y + extrapolateMotion(player.lastvy, player.vy, t) :
  720.                 player.lasty + (player.y - player.lasty) * interpolateMotion(player.lastvy, player.vy, t);
  721.             px = ratio * player.renderx;
  722.             py = ratio * player.rendery;
  723.         }
  724.  
  725.         { // Clear the background + draw grid
  726.             clearScreen(color.white, 1);  
  727.             clearScreen(color.guiblack, 0.1);
  728.  
  729.             let W = roomSetup[0].length, H = roomSetup.length, i = 0;
  730.             roomSetup.forEach((row) => {
  731.                 let j = 0;
  732.                 row.forEach((cell) => {
  733.                     let left = Math.max(0, ratio*i*global.gameWidth/W - px + global.screenWidth / 2),
  734.                         top = Math.max(0, ratio*j*global.gameHeight/H - py + global.screenHeight / 2),
  735.                         right = Math.min(global.screenWidth, (ratio*(i+1)*global.gameWidth/W - px) + global.screenWidth / 2),
  736.                         bottom = Math.min(global.screenHeight, (ratio*(j+1)*global.gameHeight/H - py) + global.screenHeight / 2);
  737.                     ctx.globalAlpha = 1;
  738.                     ctx.fillStyle = (config.graphical.screenshotMode) ? color.guiwhite : color.white;
  739.                     ctx.fillRect(left, top, right-left, bottom-top);
  740.                     ctx.globalAlpha = 0.2;
  741.                     ctx.fillStyle = (config.graphical.screenshotMode) ? color.guiwhite : getZoneColor(cell, true);
  742.                     ctx.fillRect(left, top, right-left, bottom-top);
  743.                     j++;
  744.                 });
  745.                 i++;
  746.             });
  747.             ctx.lineWidth = 1;
  748.             ctx.strokeStyle = (config.graphical.screenshotMode) ? color.guiwhite : color.guiblack;
  749.             ctx.globalAlpha = 0.05;
  750.             ctx.beginPath();    
  751.             let gridsize = 20*ratio;
  752.             for (let x=(global.screenWidth/2-px)%gridsize; x < global.screenWidth; x += gridsize) {
  753.                 ctx.moveTo(x, 0);
  754.                 ctx.lineTo(x, global.screenHeight);
  755.             }    
  756.             for (let y=(global.screenHeight/2-py)%gridsize; y < global.screenHeight; y += gridsize) {
  757.                 ctx.moveTo(0, y);
  758.                 ctx.lineTo(global.screenWidth, y);
  759.             }    
  760.             ctx.stroke();
  761.             ctx.globalAlpha = 1;
  762.         }
  763.  
  764.         { // Draw things
  765.             entities.forEach(function(instance) {    
  766.                 instance.render.x = (t >= 0) ?
  767.                     instance.x + extrapolateMotion(instance.render.lastvx, instance.vx, t) :
  768.                     instance.render.lastx + (instance.x - instance.render.lastx) * interpolateMotion(instance.render.lastvx, instance.vx, t);
  769.                 instance.render.y = (t >= 0) ?
  770.                     instance.y + extrapolateMotion(instance.render.lastvy, instance.vy, t) :
  771.                     instance.render.lasty + (instance.y - instance.render.lasty) * interpolateMotion(instance.render.lastvy, instance.vy, t);
  772.                 instance.render.f = (instance.twiggle) ?
  773.                     Math.atan2(target.y, target.x) :
  774.                     instance.render.f = instance.render.lastf + (1 + t / metrics.rendergap) * angleDifference(instance.render.lastf, instance.facing);
  775.                 let x = (instance.twiggle) ? 0 : ratio * instance.render.x - px,
  776.                     y = (instance.twiggle) ? 0 : ratio * instance.render.y - py;
  777.                 x += global.screenWidth / 2;
  778.                 y += global.screenHeight / 2;
  779.                 drawEntity(x, y, instance, ratio, 1.1, instance.render.f, false);
  780.             });
  781.             if (!config.graphical.screenshotMode) {
  782.                 entities.forEach(function(instance) {        
  783.                     let x = (instance.twiggle) ? 0 : ratio * instance.render.x - px,
  784.                         y = (instance.twiggle) ? 0 : ratio * instance.render.y - py;
  785.                     x += global.screenWidth / 2;
  786.                     y += global.screenHeight / 2;
  787.                     drawHealth(x, y, instance, ratio);
  788.                 });
  789.             }
  790.         }
  791.        
  792.         // Draw GUI
  793.         let alcoveSize = 200/Math.max(global.screenWidth, global.screenHeight * 16 / 9);
  794.         let spacing = 20;
  795.         let max = (leaderboard[0] == null) ? 1 : leaderboard[0].score;
  796.        
  797.         { // Draw messages
  798.             let vspacing = 4;
  799.             let len = 0;
  800.             let height = 18;
  801.             let x = global.screenWidth/2;
  802.             let y = spacing;
  803.             for (let i=messages.length-1; i>=0; i--) {
  804.                 let msg = messages[i],
  805.                     txt = strDecodeUTF16(msg.text),
  806.                     text = txt;//txt[0].toUpperCase() + txt.substring(1);  
  807.  
  808.                 len = measureText(text, height-4);
  809.  
  810.                 ctx.globalAlpha = 0.5 * msg.alpha;
  811.                 drawBar(x-len/2, x+len/2, y+height/2, height, color.black);
  812.  
  813.                 ctx.globalAlpha = Math.min(1, msg.alpha);
  814.                 ctx.textAlign = 'center';
  815.                 drawText(text, x, y + height-4, height-4, color.guiwhite);
  816.  
  817.                 y += (vspacing + height);
  818.                 if (msg.status > 1) {
  819.                     y -= (vspacing + height) * (1 - Math.sqrt(msg.alpha));
  820.                 }
  821.  
  822.                 if (msg.status > 1) {
  823.                     messages[i].status -= 0.05;
  824.                     messages[i].alpha += 0.05;
  825.                 } else if (i === 0 && (messages.length > 5 || Date.now() - msg.time > 10000)) {
  826.                     messages[i].status -= 0.05;
  827.                     messages[i].alpha -= 0.05;
  828.                     if (messages[i].alpha <= 0) {
  829.                         messages.splice(0, 1);
  830.                     }
  831.                 }
  832.             }
  833.             ctx.globalAlpha = 1;
  834.         }
  835.  
  836.         { // Draw skill bars
  837.             global.canSkill = gui.skills.points;
  838.  
  839.             let vspacing = 4;
  840.             let len = alcoveSize * global.screenWidth; // The 30 is for the value modifiers
  841.             let save = len;
  842.             let height = 15;
  843.             let x = spacing;
  844.             let y = global.screenHeight - spacing - height;
  845.             let ticker = 11;
  846.             gui.skills.typeData.forEach(function(skill) { // Individual skill bars
  847.                 ticker--;
  848.                 let name = skill[0],
  849.                     level = skill[1],
  850.                     col = skill[2],
  851.                     value = skill[3],
  852.                     cap = skill[4],
  853.                     maxLevel = skill[5] + 1;
  854.                 if (cap) {
  855.                     len = save;
  856.                     let max = 10,
  857.                         extension = cap > max,
  858.                         blocking = cap < maxLevel;
  859.                     if (extension) {
  860.                         len = len * (cap + 1) / max;
  861.                         max = cap + 1;
  862.                     }
  863.                     drawBar(x+height/2, x-height/2+len, y+height/2, height, color.black);
  864.                     drawBar(x+height/2, x+height/2+(len-height)*(cap/max), y+height/2, height-3, color.grey);
  865.                     drawBar(x+height/2, x+height/2+(len-height)*(level/max), y+height/2, height-3.5, getColor(col));
  866.                     if (blocking) { // Blocked-off area
  867.                         ctx.lineWidth = 1;                        
  868.                         ctx.strokeStyle = color.grey;
  869.                         for (let j=cap+1; j<max; j++) {
  870.                             drawGuiLine(
  871.                                 x + (len-height) * j / max, y+1.5 ,
  872.                                 x + (len-height) * j / max, y-3 + height
  873.                             );
  874.                         }
  875.                     }            
  876.                     ctx.strokeStyle = color.black; // Vertical dividers
  877.                     ctx.lineWidth = 1;                        
  878.                     for (let j=1; j<level+1; j++) {
  879.                         drawGuiLine(
  880.                             x + (len-height) * j / max, y+1.5,
  881.                             x + (len-height) * j / max, y-3 + height
  882.                         );
  883.                     }
  884.                     ctx.textAlign = 'center'; // Skill name
  885.                     ctx.lineWidth = 2;        
  886.                     let textcolor =  (level == max) ? getColor(col) : (!gui.skills.points || (cap !== maxLevel-1 && level == cap)) ? color.grey : color.guiwhite;
  887.                     drawText(name, Math.round(x + len / 2) + 0.5, Math.round(y + height - 5) + 0.5, height - 5, textcolor);  
  888.                     ctx.textAlign = 'right'; // Skill key
  889.                     drawText('[' + (ticker % 10) + ']', Math.round(x + len - height*0.25) - 0.5, Math.round(y + height - 6) + 0.5, height - 5, textcolor);  
  890.                     ctx.textAlign = 'left'; // Skill value
  891.                     drawText(value, Math.round(x + len + 4) + 0.5, Math.round(y + height - 5) + 0.5, height - 3, getColor(col));  
  892.                    
  893.                     y -= height + vspacing;
  894.                 }
  895.             });
  896.             if (gui.skills.points !== 0) { // Draw skillpoints to spend
  897.                 ctx.lineWidth = 4;
  898.                 ctx.textAlign = 'bottom'; ctx.textAlign = 'right';
  899.                 drawText('x' + gui.skills.points, Math.round(x + len - 2) + 0.5, Math.round(y + height - 4) + 0.5, 20, color.guiwhite);
  900.             }
  901.         }
  902.  
  903.         { // Draw name, exp and score bar
  904.             let vspacing = 4;
  905.             let len = 2 * alcoveSize * global.screenWidth;
  906.             let height = 25;
  907.             let x = (global.screenWidth - len) / 2;
  908.             let y = global.screenHeight - spacing - height;
  909.  
  910.             ctx.lineWidth = 1;
  911.             drawBar(x, x+len, y+height/2, height, color.black);
  912.             drawBar(x, x+len, y+height/2, height-3, color.grey);
  913.             drawBar(x, x+len*gui.progress, y+height/2, height-3.5, color.gold);
  914.             ctx.lineWidth = 2;
  915.             ctx.textAlign = 'center';
  916.             drawText(
  917.                 'Level ' + gui.level + ' ' + gui.type,
  918.                 Math.round(x + len/2) + 0.5, Math.round(y + height - 6) + 0.5,
  919.                 height - 4, color.guiwhite
  920.             );
  921.             height = 14;
  922.             y -= height + vspacing;
  923.             drawBar(x, x+len, y+height/2, height, color.black);
  924.             drawBar(x, x+len, y+height/2, height-3, color.grey);
  925.             let scoreFactor = (max) ? Math.min(1, gui.score/max) : 1;
  926.             drawBar(x, x+len*scoreFactor, y+height/2, height-3.5, color.green);
  927.             ctx.lineWidth = 2;
  928.             ctx.textAlign = 'center';
  929.             drawText(
  930.                 'Score: ' + handleLargeNumber(gui.score),
  931.                 Math.round(x + len/2) + 0.5, Math.round(y + height - 4) + 0.5,
  932.                 height - 2, color.guiwhite
  933.             );
  934.             ctx.lineWidth = 4;
  935.             drawText(
  936.                 strDecodeUTF16(player.name),
  937.                 Math.round(x + len/2) + 0.5, Math.round(y - 10 - vspacing) + 0.5,
  938.                 32, color.guiwhite
  939.             );
  940.         }
  941.        
  942.         { // Draw minimap and FPS monitors
  943.             let len = alcoveSize * global.screenWidth;
  944.             let height = len;
  945.             let x = global.screenWidth - len - spacing;
  946.             let y = global.screenHeight - height - spacing;    
  947.  
  948.             ctx.globalAlpha = 0.5;
  949.             let W = roomSetup[0].length, H = roomSetup.length, i = 0;
  950.             roomSetup.forEach((row) => {
  951.                 let j = 0;
  952.                 row.forEach((cell) => {
  953.                     ctx.fillStyle = getZoneColor(cell, false);
  954.                     drawGuiRect(x + i*len/W, y + (j++)*height/H, len/W, height/H);
  955.                 });
  956.                 i++;
  957.             });
  958.             ctx.fillStyle = color.grey;
  959.             drawGuiRect(x, y, len, height);
  960.             ctx.globalAlpha = 0.8;
  961.             minimap.forEach(function (o) {
  962.                 ctx.fillStyle = mixColors(getColor(o[2]), color.black, 0.5);
  963.                 drawGuiRect(x + (o[0]/global.gameWidth) * len, y + (o[1]/global.gameHeight) * height, 1, 1);
  964.             });
  965.             ctx.globalAlpha = 1;
  966.             ctx.lineWidth = 1;
  967.             ctx.strokeStyle = color.black;
  968.             drawGuiRect( // My position
  969.                 x + (player.x/global.gameWidth) * len - 1,
  970.                 y + (player.y/global.gameWidth) * height - 1,
  971.                 3, 3, true);
  972.                 ctx.lineWidth = 3;
  973.             drawGuiRect(x, y, len, height, true); // Border
  974.  
  975.             ctx.textAlign = 'right';
  976.             drawText(
  977.                 'Update Rate: ' + metrics.updatetime + 'Hz',
  978.                 x + len, y - 52,
  979.                 10, color.guiwhite
  980.             );  
  981.             drawText(
  982.                 'Latency: ' + metrics.latency + 'ms',
  983.                 x + len, y - 38,
  984.                 10, color.guiwhite
  985.             );  
  986.             drawText(
  987.                 'Client FPS: ' + metrics.rendertime,
  988.                 x + len, y - 24,
  989.                 10, color.guiwhite
  990.             );  
  991.             drawText(
  992.                 'Server Speed: ' + (100 * gui.fps).toFixed(2) + '%',
  993.                 x + len, y - 10,
  994.                 10, color.guiwhite
  995.             );  
  996.  
  997.         }
  998.  
  999.         { // Draw leaderboard
  1000.             let vspacing = 4;
  1001.             let len = alcoveSize * global.screenWidth;
  1002.             let height = 14;
  1003.             let x = global.screenWidth - len - spacing;
  1004.             let y = spacing + height + 7;    
  1005.             ctx.lineWidth = 4;        
  1006.             ctx.textAlign = 'center';
  1007.             drawText('Leaderboard:', Math.round(x + len / 2) + 0.5, Math.round(y - 6) + 0.5, height + 4, color.guiwhite);  
  1008.             let i = 0;
  1009.             leaderboard.forEach(function(entry) {
  1010.                 leaderboardScore[i] += (entry.score - leaderboardScore[i]) / 20;
  1011.                 drawBar(x, x+len, y+height/2, height, color.black);
  1012.                 drawBar(x, x+len, y+height/2, height-3, color.grey);
  1013.                 let shift = Math.min(1, entry.score / max);
  1014.                 drawBar(x, x+len*shift, y+height/2, height-3.5, getColor(entry.bar));
  1015.                  // Leadboard name + score
  1016.                 ctx.textAlign = 'center';
  1017.                 ctx.lineWidth = 2;        
  1018.                 let dash = '',
  1019.                     txt = strDecodeUTF16(entry.name),
  1020.                     lab = (txt === '') ? entry.label : ' - ' + entry.label;
  1021.                 drawText(txt + lab  + ': ' + handleLargeNumber(Math.round(leaderboardScore[i++])), Math.round(x + len / 2) + 0.5, Math.round(y + height - 5) + 0.5, height - 5, color.guiwhite);  
  1022.  
  1023.                 let picture = getEntityImageFromMockup(entry.index, entry.color),
  1024.                     position = mockups[entry.index].position,
  1025.                     scale = height / position.axis,
  1026.                     xx = x - 1.5 * height - scale * position.middle.x * 0.707,
  1027.                     yy = y + 0.5 * height + scale * position.middle.x * 0.707;
  1028.                 drawEntity(xx, yy, picture, 1 / scale, scale * scale / picture.realSize, -Math.PI/4);
  1029.  
  1030.                 y += vspacing+height;
  1031.             });
  1032.         }
  1033.  
  1034.         { // Draw upgrade menu
  1035.             if (gui.upgrades.length > 0) {
  1036.                 global.canUpgrade = true;
  1037.                 var getClassUpgradeKey = function(number) {
  1038.                     switch (number) {
  1039.                         case 0: return 'y';
  1040.                         case 1: return 'h';
  1041.                         case 2: return 'u';
  1042.                         case 3: return 'j';
  1043.                         case 4: return 'i';
  1044.                         case 5: return 'k';
  1045.                         case 6: return 'o';
  1046.                         case 7: return 'l';
  1047.                     }
  1048.                 };
  1049.                 let internalSpacing = 8;
  1050.                 let len = alcoveSize * global.screenWidth/2 * 1;
  1051.                 let height = len;
  1052.                 let x = spacing;
  1053.                 let y = spacing;
  1054.                 let ticker = 0;
  1055.                 upgradeSpin += 0.01;
  1056.  
  1057.                 let colorIndex = 10;
  1058.                 gui.upgrades.forEach(function(model) {
  1059.                     ctx.globalAlpha = 0.5;
  1060.                     ctx.fillStyle = getColor(colorIndex);
  1061.                     drawGuiRect(x, y, len, height);
  1062.                     ctx.globalAlpha = 0.1;
  1063.                     ctx.fillStyle = getColor(-10 + colorIndex++);
  1064.                     drawGuiRect(x, y, len, height*0.6);
  1065.                     ctx.fillStyle = color.black;
  1066.                     drawGuiRect(x, y+height*0.6, len, height*0.4);
  1067.                     ctx.globalAlpha = 1;    
  1068.  
  1069.                     // Find offset location with rotation
  1070.                     let picture = getEntityImageFromMockup(model[0], model[1]),
  1071.                         position = mockups[model[0]].position,
  1072.                         scale = 0.6 * len / position.axis,
  1073.                         xx = x + 0.5 * len - scale * position.middle.x * Math.cos(upgradeSpin),
  1074.                         yy = y + 0.5 * height - scale * position.middle.x * Math.sin(upgradeSpin);
  1075.                     drawEntity(xx, yy, picture, 1, scale / picture.realSize, upgradeSpin);
  1076.                    
  1077.                     ctx.textAlign = 'center'; // Tank name
  1078.                     ctx.lineWidth = 2;        
  1079.                     drawText(picture.name, Math.round(x + 0.9*len/2) + 0.5, Math.round(y + height - 6) + 0.5, height/8 - 3, color.guiwhite);
  1080.                     ctx.textAlign = 'right'; // Upgrade key
  1081.                     drawText('[' + getClassUpgradeKey(ticker) + ']', Math.round(x + len - 4) + 0.5, Math.round(y + height - 6) + 0.5, height/8 - 3, color.guiwhite);  
  1082.  
  1083.                     ctx.strokeStyle = color.black; // Already incremented, see above
  1084.                     ctx.globalAlpha = 1;    
  1085.                     ctx.lineWidth = 3;        
  1086.                     drawGuiRect(x, y, len, height, true); // Border
  1087.  
  1088.                     if (ticker++ % 2) {
  1089.                         y -= height + internalSpacing;
  1090.                         x += len + internalSpacing;
  1091.                     } else {
  1092.                         y += height + internalSpacing;
  1093.                     }
  1094.                 });
  1095.  
  1096.             } else {
  1097.                 global.canUpgrade = false;
  1098.             }
  1099.         }
  1100.  
  1101.         metrics.lastrender = global.time;
  1102.  
  1103.     } catch(error) {
  1104.         console.log(error);
  1105.     }
  1106. }
  1107.  
  1108. function gameDrawDead() {
  1109.     clearScreen(color.black, 0.5);
  1110.     ctx.textAlign = 'center';    
  1111.     ctx.lineWidth = 4;
  1112.     drawText('lol you died', global.screenWidth / 2, global.screenHeight / 2 - 40, 16, color.guiwhite);
  1113.     drawText('Final score: ' + gui.score, global.screenWidth / 2, global.screenHeight / 2, 48, color.guiwhite);
  1114.     drawText('Reload to play again.', global.screenWidth / 2, global.screenHeight / 2 + 40, 16, color.guiwhite);
  1115. }
  1116.  
  1117. function gameDrawBeforeStart() {
  1118.     clearScreen(color.white, 0.5);
  1119.     ctx.textAlign = 'center';    
  1120.     ctx.lineWidth = 4;
  1121.     drawText('Trying to connect...', global.screenWidth / 2, global.screenHeight / 2, 30, color.guiwhite);
  1122.     drawText(global.messages, global.screenWidth / 2, global.screenHeight / 2 + 30, 15, color.red);
  1123. }
  1124.  
  1125. function gameDrawDisconnected() {
  1126.     clearScreen(color.black, 0.5);
  1127.     ctx.textAlign = 'center';
  1128.     ctx.lineWidth = 4;
  1129.     drawText('Disconnected.', global.screenWidth / 2, global.screenHeight / 2, 30, color.guiwhite);
  1130.     drawText(global.messages, global.screenWidth / 2, global.screenHeight / 2 + 30, 15, color.red);
  1131. }
  1132.  
  1133. function animloop() {
  1134.     global.animLoopHandle = window.requestAnimFrame(animloop);
  1135.     player.renderv += (player.view - player.renderv) / 30;
  1136.     var ratio = (config.graphical.screenshotMode) ? 2 : Math.max(global.screenWidth / player.renderv, global.screenHeight / player.renderv / 9 * 16);
  1137.  
  1138.     // Draw the game
  1139.     if (!global.disconnected) {
  1140.         if (global.gameStart) {    
  1141.             global.time = Date.now();  
  1142.             if (global.time - lastPing > 1000) { // Latency
  1143.                 // Do ping.
  1144.                 socket.emit('pingcheck', global.time);
  1145.                 lastPing = global.time;
  1146.                 // Do rendering speed.
  1147.                 metrics.rendertime = renderTimes;
  1148.                 renderTimes = 0;
  1149.                 // Do update rate.
  1150.                 metrics.updatetime = updateTimes;
  1151.                 updateTimes = 0;
  1152.             }      
  1153.             metrics.lag = global.time - player.time;
  1154.             gameDraw(ratio);
  1155.         } else {
  1156.             gameDrawBeforeStart();
  1157.         }
  1158.         if (global.died) {
  1159.             gameDrawDead();      
  1160.         }
  1161.     } else {
  1162.         gameDraw(ratio);
  1163.         gameDrawDisconnected();
  1164.     }
  1165.  
  1166.     global.time = (new Date()).getTime();
  1167. }
  1168.  
  1169. window.addEventListener('resize', resize);
  1170.  
  1171. function resize() {
  1172.     if (!socket) return;
  1173.  
  1174.     player.screenWidth = c.width = global.screenWidth = global.playerType == 'player' ? window.innerWidth : global.gameWidth;
  1175.     player.screenHeight = c.height = global.screenHeight = global.playerType == 'player' ? window.innerHeight : global.gameHeight;
  1176.  
  1177.     socket.emit('windowResized', { screenWidth: global.screenWidth, screenHeight: global.screenHeight });
  1178. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement