socket.on('1', function() { // Fire food. for(var i=0; i<currentPlayer.cells.length; i++) { if(((currentPlayer.cells[i].mass >= c.defaultPlayerMass + c.fireFood) && c.fireFood > 0) || (currentPlayer.cells[i].mass >= 20 && c.fireFood === 0)){ var masa = 1; if(c.fireFood > 0) masa = c.fireFood; else masa = currentPlayer.cells[i].mass*0.1; currentPlayer.cells[i].mass -= masa; currentPlayer.massTotal -=masa; massFood.push({ id: currentPlayer.id, num: i, masa: masa, hue: currentPlayer.hue, target: { x: currentPlayer.x - currentPlayer.cells[i].x + currentPlayer.target.x, y: currentPlayer.y - currentPlayer.cells[i].y + currentPlayer.target.y }, x: currentPlayer.cells[i].x, y: currentPlayer.cells[i].y, radius: util.massToRadius(masa), speed: 25 }); } } });
function splitCell(cell) { if(cell.mass >= c.defaultPlayerMass*2) { cell.mass = cell.mass/2; cell.radius = util.massToRadius(cell.mass); currentPlayer.cells.push({ mass: cell.mass, x: cell.x, y: cell.y, radius: cell.radius, speed: 25 }); } }
function addFood(toAdd) { var radius = util.massToRadius(c.foodMass); while (toAdd--) { var position = c.foodUniformDisposition ? util.uniformPosition(food, radius) : util.randomPosition(radius); food.push({ // Make IDs unique. id: ((new Date()).getTime() + '' + food.length) >>> 0, x: position.x, y: position.y, radius: radius, mass: Math.random() + 2, hue: Math.round(Math.random() * 360) }); } }
socket.on('gotit', function (player) { console.log('[INFO] Player ' + player.name + ' connecting!'); if (util.findIndex(users, player.id) > -1) { console.log('[INFO] Player ID is already connected, kicking.'); socket.disconnect(); } else if (!util.validNick(player.name)) { socket.emit('kick', 'Invalid username.'); socket.disconnect(); } else { console.log('[INFO] Player ' + player.name + ' connected!'); sockets[player.id] = socket; var radius = util.massToRadius(c.defaultPlayerMass); var position = c.newPlayerInitialPosition == 'farthest' ? util.uniformPosition(users, radius) : util.randomPosition(radius); player.x = position.x; player.y = position.y; player.target.x = 0; player.target.y = 0; if(type === 'player') { player.cells = [{ mass: c.defaultPlayerMass, x: position.x, y: position.y, radius: radius }]; player.massTotal = c.defaultPlayerMass; } else { player.cells = []; player.massTotal = 0; } player.hue = Math.round(Math.random() * 360); currentPlayer = player; currentPlayer.lastHeartbeat = new Date().getTime(); users.push(currentPlayer); io.emit('playerJoin', { name: currentPlayer.name }); socket.emit('gameSetup', { gameWidth: c.gameWidth, gameHeight: c.gameHeight }); console.log('Total players: ' + users.length); } });
function addVirus(toAdd) { while (toAdd--) { var mass = util.randomInRange(c.virus.defaultMass.from, c.virus.defaultMass.to, true); var radius = util.massToRadius(mass); var position = c.virusUniformDisposition ? util.uniformPosition(virus, radius) : util.randomPosition(radius); virus.push({ id: ((new Date()).getTime() + '' + virus.length) >>> 0, x: position.x, y: position.y, radius: radius, mass: mass, fill: c.virus.fill, stroke: c.virus.stroke, strokeWidth: c.virus.strokeWidth }); } }
function movePlayer(player) { var x =0,y =0; for(var i=0; i<player.cells.length; i++) { var target = { x: player.x - player.cells[i].x + player.target.x, y: player.y - player.cells[i].y + player.target.y }; var dist = Math.sqrt(Math.pow(target.y, 2) + Math.pow(target.x, 2)); var deg = Math.atan2(target.y, target.x); var slowDown = 1; if(player.cells[i].speed <= 6.25) { slowDown = util.log(player.cells[i].mass, c.slowBase) - initMassLog + 1; } var deltaY = player.cells[i].speed * Math.sin(deg)/ slowDown; var deltaX = player.cells[i].speed * Math.cos(deg)/ slowDown; if(player.cells[i].speed > 6.25) { player.cells[i].speed -= 0.5; } if (dist < (50 + player.cells[i].radius)) { deltaY *= dist / (50 + player.cells[i].radius); deltaX *= dist / (50 + player.cells[i].radius); } if (!isNaN(deltaY)) { player.cells[i].y += deltaY; } if (!isNaN(deltaX)) { player.cells[i].x += deltaX; } // Find best solution. for(var j=0; j<player.cells.length; j++) { if(j != i && player.cells[i] !== undefined) { var distance = Math.sqrt(Math.pow(player.cells[j].y-player.cells[i].y,2) + Math.pow(player.cells[j].x-player.cells[i].x,2)); var radiusTotal = (player.cells[i].radius + player.cells[j].radius); if(distance < radiusTotal) { if(player.lastSplit > new Date().getTime() - 1000 * c.mergeTimer) { if(player.cells[i].x < player.cells[j].x) { player.cells[i].x--; } else if(player.cells[i].x > player.cells[j].x) { player.cells[i].x++; } if(player.cells[i].y < player.cells[j].y) { player.cells[i].y--; } else if((player.cells[i].y > player.cells[j].y)) { player.cells[i].y++; } } else if(distance < radiusTotal / 1.75) { player.cells[i].mass += player.cells[j].mass; player.cells[i].radius = util.massToRadius(player.cells[i].mass); player.cells.splice(j, 1); } } } } if(player.cells.length > i) { var borderCalc = player.cells[i].radius / 3; if (player.cells[i].x > c.gameWidth - borderCalc) { player.cells[i].x = c.gameWidth - borderCalc; } if (player.cells[i].y > c.gameHeight - borderCalc) { player.cells[i].y = c.gameHeight - borderCalc; } if (player.cells[i].x < borderCalc) { player.cells[i].x = borderCalc; } if (player.cells[i].y < borderCalc) { player.cells[i].y = borderCalc; } x += player.cells[i].x; y += player.cells[i].y; } } player.x = x/player.cells.length; player.y = y/player.cells.length; }
function tickPlayer(currentPlayer) { if(currentPlayer.lastHeartbeat < new Date().getTime() - c.maxHeartbeatInterval) { sockets[currentPlayer.id].emit('kick', 'Last heartbeat received over ' + c.maxHeartbeatInterval + ' ago.'); sockets[currentPlayer.id].disconnect(); } movePlayer(currentPlayer); function funcFood(f) { return SAT.pointInCircle(new V(f.x, f.y), playerCircle); } function deleteFood(f) { food[f] = {}; food.splice(f, 1); } function eatMass(m) { if(SAT.pointInCircle(new V(m.x, m.y), playerCircle)){ if(m.id == currentPlayer.id && m.speed > 0 && z == m.num) return false; if(currentCell.mass > m.masa * 1.1) return true; } return false; } function check(user) { for(var i=0; i<user.cells.length; i++) { if(user.cells[i].mass > 10 && user.id !== currentPlayer.id) { var response = new SAT.Response(); var collided = SAT.testCircleCircle(playerCircle, new C(new V(user.cells[i].x, user.cells[i].y), user.cells[i].radius), response); if (collided) { response.aUser = currentCell; response.bUser = { id: user.id, name: user.name, x: user.cells[i].x, y: user.cells[i].y, num: i, mass: user.cells[i].mass }; playerCollisions.push(response); } } } return true; } function collisionCheck(collision) { if (collision.aUser.mass > collision.bUser.mass * 1.1 && collision.aUser.radius > Math.sqrt(Math.pow(collision.aUser.x - collision.bUser.x, 2) + Math.pow(collision.aUser.y - collision.bUser.y, 2))*1.75) { console.log('[DEBUG] Killing user: '******'[DEBUG] Collision info:'); console.log(collision); var numUser = util.findIndex(users, collision.bUser.id); if (numUser > -1) { if(users[numUser].cells.length > 1) { users[numUser].massTotal -= collision.bUser.mass; users[numUser].cells.splice(collision.bUser.num, 1); } else { users.splice(numUser, 1); io.emit('playerDied', { name: collision.bUser.name }); sockets[collision.bUser.id].emit('RIP'); } } currentPlayer.massTotal += collision.bUser.mass; collision.aUser.mass += collision.bUser.mass; } } for(var z=0; z<currentPlayer.cells.length; z++) { var currentCell = currentPlayer.cells[z]; var playerCircle = new C( new V(currentCell.x, currentCell.y), currentCell.radius ); var foodEaten = food.map(funcFood) .reduce( function(a, b, c) { return b ? a.concat(c) : a; }, []); foodEaten.forEach(deleteFood); var massEaten = massFood.map(eatMass) .reduce(function(a, b, c) {return b ? a.concat(c) : a; }, []); var virusCollision = virus.map(funcFood) .reduce( function(a, b, c) { return b ? a.concat(c) : a; }, []); if(virusCollision > 0 && currentCell.mass > virus[virusCollision].mass) { sockets[currentPlayer.id].emit('virusSplit', z); } var masaGanada = 0; for(var m=0; m<massEaten.length; m++) { masaGanada += massFood[massEaten[m]].masa; massFood[massEaten[m]] = {}; massFood.splice(massEaten[m],1); for(var n=0; n<massEaten.length; n++) { if(massEaten[m] < massEaten[n]) { massEaten[n]--; } } } if(typeof(currentCell.speed) == "undefined") currentCell.speed = 6.25; masaGanada += (foodEaten.length * c.foodMass); currentCell.mass += masaGanada; currentPlayer.massTotal += masaGanada; currentCell.radius = util.massToRadius(currentCell.mass); playerCircle.r = currentCell.radius; tree.clear(); users.forEach(tree.put); var playerCollisions = []; var otherUsers = tree.get(currentPlayer, check); playerCollisions.forEach(collisionCheck); } }
io.on('connection', function (socket) { console.log('A user connected!', socket.handshake.query.type); var type = socket.handshake.query.type; var radius = util.massToRadius(c.defaultPlayerMass); var position = c.newPlayerInitialPosition == 'farthest' ? util.uniformPosition(users, radius) : util.randomPosition(radius); var cells = []; var massTotal = 0; if(type === 'player') { cells = [{ mass: c.defaultPlayerMass, x: position.x, y: position.y, radius: radius }]; massTotal = c.defaultPlayerMass; } var currentPlayer = { id: socket.id, x: position.x, y: position.y, w: c.defaultPlayerMass, h: c.defaultPlayerMass, cells: cells, massTotal: massTotal, hue: Math.round(Math.random() * 360), type: type, lastHeartbeat: new Date().getTime(), target: { x: 0, y: 0 } }; socket.on('gotit', function (player) { console.log('[INFO] Player ' + player.name + ' connecting!'); if (util.findIndex(users, player.id) > -1) { console.log('[INFO] Player ID is already connected, kicking.'); socket.disconnect(); } else if (!util.validNick(player.name)) { socket.emit('kick', 'Invalid username.'); socket.disconnect(); } else { console.log('[INFO] Player ' + player.name + ' connected!'); sockets[player.id] = socket; var radius = util.massToRadius(c.defaultPlayerMass); var position = c.newPlayerInitialPosition == 'farthest' ? util.uniformPosition(users, radius) : util.randomPosition(radius); player.x = position.x; player.y = position.y; player.target.x = 0; player.target.y = 0; if(type === 'player') { player.cells = [{ mass: c.defaultPlayerMass, x: position.x, y: position.y, radius: radius }]; player.massTotal = c.defaultPlayerMass; } else { player.cells = []; player.massTotal = 0; } player.hue = Math.round(Math.random() * 360); currentPlayer = player; currentPlayer.lastHeartbeat = new Date().getTime(); users.push(currentPlayer); io.emit('playerJoin', { name: currentPlayer.name }); socket.emit('gameSetup', { gameWidth: c.gameWidth, gameHeight: c.gameHeight }); console.log('Total players: ' + users.length); } }); socket.on('pingcheck', function () { socket.emit('pongcheck'); }); socket.on('windowResized', function (data) { currentPlayer.screenWidth = data.screenWidth; currentPlayer.screenHeight = data.screenHeight; }); socket.on('respawn', function () { if (util.findIndex(users, currentPlayer.id) > -1) users.splice(util.findIndex(users, currentPlayer.id), 1); socket.emit('welcome', currentPlayer); console.log('[INFO] User ' + currentPlayer.name + ' respawned!'); }); socket.on('disconnect', function () { if (util.findIndex(users, currentPlayer.id) > -1) users.splice(util.findIndex(users, currentPlayer.id), 1); console.log('[INFO] User ' + currentPlayer.name + ' disconnected!'); socket.broadcast.emit('playerDisconnect', { name: currentPlayer.name }); }); socket.on('playerChat', function(data) { var _sender = data.sender.replace(/(<([^>]+)>)/ig, ''); var _message = data.message.replace(/(<([^>]+)>)/ig, ''); if (c.logChat === 1) { console.log('[CHAT] [' + (new Date()).getHours() + ':' + (new Date()).getMinutes() + '] ' + _sender + ': ' + _message); } socket.broadcast.emit('serverSendPlayerChat', {sender: _sender, message: _message.substring(0,35)}); }); socket.on('pass', function(data) { if (data[0] === c.adminPass) { console.log('[ADMIN] ' + currentPlayer.name + ' just logged in as an admin!'); socket.emit('serverMSG', 'Welcome back ' + currentPlayer.name); socket.broadcast.emit('serverMSG', currentPlayer.name + ' just logged in as admin!'); currentPlayer.admin = true; } else { console.log('[ADMIN] ' + currentPlayer.name + ' attempted to log in with incorrect password.'); socket.emit('serverMSG', 'Password incorrect, attempt logged.'); // TODO: Actually log incorrect passwords. } }); socket.on('kick', function(data) { if (currentPlayer.admin) { var reason = ''; var worked = false; for (var e = 0; e < users.length; e++) { if (users[e].name === data[0] && !users[e].admin && !worked) { if (data.length > 1) { for (var f = 1; f < data.length; f++) { if (f === data.length) { reason = reason + data[f]; } else { reason = reason + data[f] + ' '; } } } if (reason !== '') { console.log('[ADMIN] User ' + users[e].name + ' kicked successfully by ' + currentPlayer.name + ' for reason ' + reason); } else { console.log('[ADMIN] User ' + users[e].name + ' kicked successfully by ' + currentPlayer.name); } socket.emit('serverMSG', 'User ' + users[e].name + ' was kicked by ' + currentPlayer.name); sockets[users[e].id].emit('kick', reason); sockets[users[e].id].disconnect(); users.splice(e, 1); worked = true; } } if (!worked) { socket.emit('serverMSG', 'Could not locate user or user is an admin.'); } } else { console.log('[ADMIN] ' + currentPlayer.name + ' is trying to use -kick but isn\'t an admin.'); socket.emit('serverMSG', 'You are not permitted to use this command.'); } }); // Heartbeat function, update everytime. socket.on('0', function(target) { currentPlayer.lastHeartbeat = new Date().getTime(); if (target.x !== currentPlayer.x || target.y !== currentPlayer.y) { currentPlayer.target = target; } }); socket.on('1', function() { // Fire food. for(var i=0; i<currentPlayer.cells.length; i++) { if(((currentPlayer.cells[i].mass >= c.defaultPlayerMass + c.fireFood) && c.fireFood > 0) || (currentPlayer.cells[i].mass >= 20 && c.fireFood === 0)){ var masa = 1; if(c.fireFood > 0) masa = c.fireFood; else masa = currentPlayer.cells[i].mass*0.1; currentPlayer.cells[i].mass -= masa; currentPlayer.massTotal -=masa; massFood.push({ id: currentPlayer.id, num: i, masa: masa, hue: currentPlayer.hue, target: { x: currentPlayer.x - currentPlayer.cells[i].x + currentPlayer.target.x, y: currentPlayer.y - currentPlayer.cells[i].y + currentPlayer.target.y }, x: currentPlayer.cells[i].x, y: currentPlayer.cells[i].y, radius: util.massToRadius(masa), speed: 25 }); } } }); socket.on('2', function(virusCell) { function splitCell(cell) { if(cell.mass >= c.defaultPlayerMass*2) { cell.mass = cell.mass/2; cell.radius = util.massToRadius(cell.mass); currentPlayer.cells.push({ mass: cell.mass, x: cell.x, y: cell.y, radius: cell.radius, speed: 25 }); } } if(currentPlayer.cells.length < c.limitSplit && currentPlayer.massTotal >= c.defaultPlayerMass*2) { //Split single cell from virus if(virusCell) { splitCell(currentPlayer.cells[virusCell]); } else { //Split all cells if(currentPlayer.cells.length < c.limitSplit && currentPlayer.massTotal >= c.defaultPlayerMass*2) { var numMax = currentPlayer.cells.length; for(var d=0; d<numMax; d++) { splitCell(currentPlayer.cells[d]); } } } currentPlayer.lastSplit = new Date().getTime(); } }); });