Advertisement
Guest User

bot

a guest
Mar 21st, 2016
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var PlayerTracker = require('../PlayerTracker');
  2. var gameServer = require('../GameServer');
  3.  
  4. function BotPlayer() {
  5.     PlayerTracker.apply(this, Array.prototype.slice.call(arguments));
  6.     //this.color = gameServer.getRandomColor();
  7.  
  8.     // AI only
  9.     this.gameState = 0;
  10.  
  11.     this.predators = []; // List of cells that can eat this bot
  12.     this.threats = []; // List of cells that can eat this bot but are too far away
  13.     this.splitThreats = []; // Sublist of threats but split threats are up to 3.5x size of cell
  14.     this.prey = []; // List of cells that can be eaten by this bot
  15.     this.food = [];
  16.     this.ejectedMass = [];
  17.     this.virus = []; // List of viruses
  18.     this.obstacles = []; // Viruses or same-team cells that will be avoided
  19.  
  20.     this.splitCooldown = 0; // When I split, this will be 16
  21.     this.juke = false;
  22.  
  23.     this.target;
  24.     this.targetVirus; // Virus used to shoot into the target
  25.     this.virusShots = 0; // Amount of pressed W to explode target via target virus
  26.  
  27.     this.ejectMass = 0; // Amount of times to eject mass
  28.     this.mouse = {
  29.         x: 0,
  30.         y: 0
  31.     };
  32.     this.targetPos = {
  33.         x: 0,
  34.         y: 0
  35.     };
  36. }
  37.  
  38. module.exports = BotPlayer;
  39. BotPlayer.prototype = new PlayerTracker();
  40.  
  41. // Functions
  42.  
  43. BotPlayer.prototype.getLowestCell = function() {
  44.     // Gets the cell with the lowest mass
  45.     if (this.cells.length <= 0) {
  46.         return null; // Error!
  47.     }
  48.  
  49.     // Starting cell
  50.     var lowest = this.cells[0];
  51.     for (i = 1; i < this.cells.length; i++) {
  52.         if (lowest.mass > this.cells[i].mass) {
  53.             lowest = this.cells[i];
  54.         }
  55.     }
  56.     return lowest;
  57. };
  58.  
  59. BotPlayer.prototype.getHighestCell = function() {
  60.     // Gets the cell with the highest mass
  61.     if (this.cells.length <= 0) {
  62.         return null; // Error!
  63.     }
  64.  
  65.     // Starting cell
  66.     var highest = this.cells[0];
  67.     for (i = 1; i < this.cells.length; i++) {
  68.         if (highest.mass > this.cells[i].mass) {
  69.             highest = this.cells[i];
  70.         }
  71.     }
  72.     return highest;
  73. };
  74.  
  75. // Don't override, testing to use more accurate way.
  76. /*
  77. BotPlayer.prototype.updateSightRange = function() { // For view distance
  78.     var range = 1000; // Base sight range
  79.  
  80.     if (this.cells[0]) {
  81.         range += this.cells[0].getSize() * 2.5;
  82.     }
  83.  
  84.     this.sightRangeX = range;
  85.     this.sightRangeY = range;
  86. }; */
  87.  
  88. BotPlayer.prototype.update = function() { // Overrides the update function from player tracker
  89.     // Remove nodes from visible nodes if possible
  90.     for (var i = 0; i < this.nodeDestroyQueue.length; i++) {
  91.         var index = this.visibleNodes.indexOf(this.nodeDestroyQueue[i]);
  92.         if (index > -1) {
  93.             this.visibleNodes.splice(index, 1);
  94.         }
  95.     }
  96.  
  97.     // Respawn if bot is dead
  98.     if (this.cells.length <= 0) {
  99.         this.gameServer.gameMode.onPlayerSpawn(this.gameServer, this);
  100.         if (this.cells.length == 0) {
  101.             // If the bot cannot spawn any cells, then disconnect it
  102.             this.socket.close();
  103.             return;
  104.         }
  105.     }
  106.  
  107.     if (this.splitCooldown > 0) this.splitCooldown -= 1;
  108.     this.shouldUpdateNodes();
  109.  
  110.     if (Math.random() > 0.5) return;
  111.     setTimeout(function() {
  112.         // Calculate what should I do
  113.         var cell = this.getLowestCell();
  114.         this.clearLists();
  115.  
  116.         for (var i in this.visibleNodes) {
  117.             var check = this.visibleNodes[i];
  118.             this.addCellToList(cell, check);
  119.         }
  120.  
  121.         // Get gamestate
  122.         var newState = this.getState(cell);
  123.         if ((newState != this.gameState) && (newState != 4)) {
  124.             // Clear target
  125.             this.target = null;
  126.         }
  127.         this.gameState = newState;
  128.  
  129.         // Action
  130.         this.decide(cell);
  131.     }.bind(this), 0);
  132.  
  133.     // Reset queues
  134.     this.nodeDestroyQueue = [];
  135.     this.nodeAdditionQueue = [];
  136. };
  137.  
  138. BotPlayer.prototype.shouldUpdateNodes = function() {
  139.     if ((this.tickViewBox <= 0) && (this.gameServer.run)) {
  140.         this.visibleNodes = this.calcViewBox();
  141.         this.tickViewBox = 2;
  142.     } else {
  143.         this.tickViewBox--;
  144.     }
  145. };
  146.  
  147. BotPlayer.prototype.getState = function(cell) {
  148.     if (this.gameState == 4) {
  149.         // Continue to shoot viruses
  150.         return 4;
  151.     }
  152.  
  153.     // Check for predators
  154.     if (this.predators.length <= 0) {
  155.         if (this.prey.length > 0) {
  156.             return 3;
  157.         }
  158.         else if (this.food.length > 0) {
  159.             return 1;
  160.         }
  161.     } else {
  162.         if (this.cells.length == 1 && cell.mass > 180) {
  163.             var t = this.getBiggest(this.threats);
  164.             var tl = this.findNearbyVirus(t, 500, this.virus);
  165.             if (tl != false) {
  166.                 this.target = t;
  167.                 this.targetVirus = tl;
  168.                 return 4;
  169.             } else return 2; // Run
  170.         } else {
  171.             // Run
  172.             return 2;
  173.         }
  174.     }
  175.  
  176.     return 0; // None
  177. };
  178.  
  179. BotPlayer.prototype.decide = function(cell) {
  180.     switch (this.gameState) {
  181.         case 1: // Target food
  182.             var target = this.food[0];
  183.  
  184.             var angle = this.angle(target.position, cell.position);
  185.             var dist = this.distance(target.position, cell.position);
  186.             angle = this.avoidObstacles(cell, angle); // Avoid obstacles in the way
  187.  
  188.             var x1 = cell.position.x + (dist * Math.sin(angle));
  189.             var y1 = cell.position.y + (dist * Math.cos(angle));
  190.  
  191.             this.updateMouse(x1, y1);
  192.             break;
  193.         case 2: // Run from predators
  194.             var enemyCenter = this.combineVectors(this.predators);
  195.             // Get angle from enemy center to my cell
  196.             var angle = this.angle(cell.position, enemyCenter);
  197.  
  198.             // Direction to move
  199.             var x1 = cell.position.x + (700 * Math.sin(angle));
  200.             var y1 = cell.position.y + (700 * Math.cos(angle));
  201.  
  202.             this.updateMouse(x1, y1);
  203.  
  204.             if (this.juke) {
  205.                 // Juking
  206.                 this.gameServer.splitCells(this);
  207.             }
  208.             break;
  209.         case 3: // Target prey
  210.  
  211.             var target = this.bestPrey(cell, this.prey);
  212.             var angle = this.angle(target.position, cell.position);
  213.             var dist = this.distance(target.position, cell.position);
  214.             angle = this.avoidObstacles(cell, angle); // Avoid obstacles in the way
  215.  
  216.             var x1 = cell.position.x + (dist * Math.sin(angle));
  217.             var y1 = cell.position.y + (dist * Math.cos(angle));
  218.  
  219.             this.updateMouse(x1, y1);
  220.  
  221.             // Look if I can splitkill it
  222.             if (this.splitCooldown <= 0 && this.canSplitkill(cell, target) && this.cells.length < 3) {
  223.                 // I can do it
  224.                 // See if I will have problems if I split
  225.                 if (this.splitThreats.length > 0) {
  226.                     if (this.getBiggest(this.splitThreats).mass > this.mass * 1.3) {
  227.                         break; // I will
  228.                     }
  229.                 }
  230.  
  231.                 // Update mouse to directly follow the prey
  232.                 this.updateMouse(target.position.x, target.position.y);
  233.  
  234.                 // Split!
  235.                 this.gameServer.splitCells(this);
  236.                 this.splitCooldown = 16;
  237.             }
  238.             break;
  239.         case 4: // Shoot virus
  240.               if ((!this.target) || (!this.targetVirus) || (!this.cells.length == 1) ||
  241.                   (this.visibleNodes.indexOf(this.target) == -1) || (this.visibleNodes.indexOf(this.targetVirus) == -1)) {
  242.  
  243.                   this.gameState = 0; // Reset
  244.                   this.target = null;
  245.                   break;
  246.               }
  247.  
  248.               // Make sure target is within range
  249.               var dist = this.getDist(this.targetVirus, this.target) - (this.target.getSize() + 100);
  250.               if (dist > 500) {
  251.                   this.gameState = 0; // Reset
  252.                   this.target = null;
  253.                   break;
  254.               }
  255.  
  256.               // Find angle of vector between target and virus
  257.               var angle = this.getAngle(this.targetVirus, this.target);
  258.  
  259.               // Get my angle to target virus
  260.               var ourAngle = this.getAngle(cell, this.targetVirus);
  261.  
  262.               // Check if I'm in position
  263.               if ((ourAngle <= (angle + .25)) && (ourAngle >= (angle - .25))) {
  264.                   // In position!
  265.                   this.updateMouse(this.targetVirus.position.x, this.targetVirus.position.y);
  266.  
  267.                   // Shoot W
  268.                   if (this.virusShots <= this.gameServer.config.virusFeedAmount) {
  269.                       this.gameServer.ejectMass(this);
  270.                       this.virusShots++;
  271.                       break;
  272.                   }
  273.  
  274.                   // Cleanup
  275.                   this.gameState = 0; // Reset
  276.                   this.virusShots = 0;
  277.                   this.target = null;
  278.               } else {
  279.                   // Move to position
  280.                   var r = cell.getSize();
  281.                   var x1 = this.targetVirus.position.x + ((350 + r) * Math.sin(angle));
  282.                   var y1 = this.targetVirus.position.y + ((350 + r) * Math.cos(angle));
  283.                   this.updateMouse(x1, y1);
  284.               }
  285.           default:
  286.             break;
  287.     }
  288.  
  289.     // Recombining
  290.     if (this.cells.length > 1) {
  291.         var r = 0;
  292.         // Get amount of cells that can merge
  293.         for (var i in this.cells) {
  294.             if (this.cells[i].shouldRecombine) {
  295.                 r++;
  296.             }
  297.         }
  298.         // Merge
  299.         if (r >= 2) {
  300.             this.updateMouse(this.centerPos.x, this.centerPos.y);
  301.         }
  302.     }
  303. };
  304.  
  305. BotPlayer.prototype.updateMouse = function(xPos, yPos) {
  306.     this.targetPos = {
  307.         x: xPos,
  308.         y: yPos
  309.     },
  310.     this.mouse = {
  311.         x: this.targetPos.x,
  312.         y: this.targetPos.y
  313.     };
  314. };
  315.  
  316. BotPlayer.prototype.avoidObstacles = function(cell, angle) {
  317.     // Sum up all of the vector angles of obstacles to cell and react against it
  318.     var angleSum = 0;
  319.     var collided = this.collisionFromList(cell, this.obstacles);
  320.     if (collided.length == 0) return angle; // Not to return NaN
  321.  
  322.     for (var i = 0; i < collided.length; i++) {
  323.         angleSum += this.angle(cell.position, collided[i].position);
  324.     }
  325.  
  326.     angleSum /= collided.length; // Average out the angle sum
  327.  
  328.     // Find closest available edge
  329.     angleSum += 1.57;
  330.  
  331.     return angle + angleSum;
  332. };
  333.  
  334. BotPlayer.prototype.collisionFromList = function(cell, list) {
  335.     var collided = [];
  336.  
  337.     for (var i = 0; i < list.length; i++) {
  338.         var check = list[i];
  339.         if (this.edgeDistance(cell, check) < 0) collided.push(check);
  340.     }
  341.  
  342.     return collided;
  343. };
  344.  
  345. BotPlayer.prototype.clearLists = function() {
  346.     this.predators = [];
  347.     this.threats = [];
  348.     this.splitThreats = [];
  349.     this.prey = [];
  350.     this.food = [];
  351.     this.ejectedMass = [];
  352.     this.virus = [];
  353.     this.obstacles = [];
  354. };
  355.  
  356. // Library of subfunctions which are directions to what should I do
  357.  
  358. BotPlayer.prototype.getCheckStatus = function(cell, check) {
  359.     // 0 - Prey, 1 - Predator, 2 - Threat, 3 - Split threat, 4 - Obstacle
  360.     var dist = this.distance(cell.position, check.position);
  361.     if (this.isVirus(check)) {
  362.         // Check collision distance
  363.         if (cell.mass / 1.3 > check.mass) {
  364.             return 4; // Obstacle - virus
  365.         }
  366.     } else if (this.isMyTeam(check)) {
  367.         // Check collision distance
  368.         if (dist < this.collideDistance(cell, check) * 1.2) {
  369.             return 4; // Obstacle - same team cell
  370.         }
  371.     } else {
  372.         var eat = this.checkEat(cell, check);
  373.         if (eat == 1) return 0; // Prey
  374.         if (eat == -1) {
  375.             // If I am too close to it, I should fear it
  376.             // My fear distance should be maximum when the cell wants to splitkill me
  377.             // And be minimum when the cell is a lot of times larger than me
  378.             // I'm going to use Math.sin to do this
  379.             var sizeDiff = check.getSize() - cell.getSize();
  380.             var fearDistance = (Math.sin(Math.min(sizeDiff / 50, Math.PI * 1.5)) + 1) * 300 + 50;
  381.             if (dist < fearDistance) {
  382.                 if (this.edgeDistance(cell, check) < 0) this.juke = true; // Run
  383.                 return 1; // Predator
  384.             } else {
  385.                 if (check.mass / 3.5 > cell.mass || dist < fearDistance * 1.5) return 3; // Split threat
  386.                 return 2; // Threat
  387.             }
  388.         }
  389.     }
  390.     return -1; // Nothing
  391. };
  392.  
  393. BotPlayer.prototype.addCellToList = function(cell, check) {
  394.     // Check for cell type and return status
  395.     if (check.owner == cell.owner) {
  396.         // Cannot target/be targeted by owner cells
  397.         return;
  398.     }
  399.  
  400.     var returnStatus = -1;
  401.     if (check.cellType != 1) returnStatus = this.getCheckStatus(cell, check); // Don't check status for pellets
  402.     switch (check.cellType) {
  403.         case 0: // Player cell
  404.             if (returnStatus == 0) this.prey.push(check);
  405.             if (returnStatus == 1) {
  406.                 this.predators.push(check);
  407.                 this.threats.push(check);
  408.                 this.splitThreats.push(check);
  409.             }
  410.             if (returnStatus == 2) {
  411.                 this.threats.push(check);
  412.                 this.splitThreats.push(check);
  413.             }
  414.             if (this.returnStatus == 3) this.splitThreats.push(check);
  415.             if (this.returnStatus == 4) this.obstacles.push(check);
  416.             break;
  417.         case 1: // Food
  418.             this.food.push(check);
  419.             break;
  420.         case 2: // Virus
  421.             this.virus.push(check);
  422.             if (returnStatus == 4) this.obstacles.push(check);
  423.             break;
  424.         case 3: // Ejected mass
  425.             if (returnStatus == 0) this.food.push(check);
  426.             break;
  427.         default:
  428.             break;
  429.     }
  430. };
  431.  
  432. BotPlayer.prototype.checkEat = function(cell, check) {
  433.     // -1 It can eat me, 0 Nothing, 1 I can eat it
  434.     var mergedMass = 0;
  435.     var isCheckMerging = false;
  436.     if (check.owner) {
  437.         for (var i = 0; i < check.owner.cells.length; i++) {
  438.             var c = check.owner.cells[i];
  439.             if (c.shouldRecombine) {
  440.                 mergedMass += c.mass;
  441.                 if (c.nodeId == check.nodeId) isCheckMerging = true;
  442.             }
  443.         }
  444.     }
  445.     if (isCheckMerging) {
  446.         if (mergedMass / 1.3 > cell.mass) return -1;
  447.         if (cell.mass / 1.3 > mergedMass) return 1;
  448.     } else {
  449.         if (check.mass / 1.3 > cell.mass) return -1;
  450.         if (cell.mass / 1.3 > check.mass) return 1;
  451.     }
  452.     // Every eating check has passed
  453.     return 0;
  454. };
  455.  
  456. BotPlayer.prototype.combineVectors = function(list) {
  457.     // Average position of all cells from the list
  458.     if (list.length == 0) return null; // List is empty
  459.     var xs = 0, ys = 0;
  460.  
  461.     for (var i in list) {
  462.         var check = list[i];
  463.         xs += check.position.x;
  464.         ys += check.position.y;
  465.     }
  466.  
  467.     xs /= list.length;
  468.     ys /= list.length;
  469.  
  470.     return {
  471.         x: xs,
  472.         y: ys
  473.     };
  474. };
  475.  
  476. BotPlayer.prototype.findNearbyVirus = function(cell, checkDist, list) {
  477.     var r = cell.getSize() + 100; // Gets radius + virus radius
  478.     for (var i = 0; i < list.length; i++) {
  479.         var check = list[i];
  480.         var dist = this.distance(cell, check) - r;
  481.         if (checkDist > dist) {
  482.             return check;
  483.         }
  484.     }
  485.     return false; // Returns a bool if no nearby viruses are found
  486. };
  487.  
  488. BotPlayer.prototype.bestPrey = function(cell, list) {
  489.     // Finds the best prey to target
  490.     if (list.length == 0) return null; // List is empty
  491.  
  492.     var best = list[0];
  493.     var bestCoefficient = this.distance(cell.position, best.position) - best.mass * 5;
  494.  
  495.     for (var i = 1; i < list.length; i++) {
  496.         var check = list[i];
  497.         var checkDist = this.distance(cell.position, check.position);
  498.         var coefficient = checkDist - check.size * 8;
  499.         if (bestCoefficient > coefficient) {
  500.             // Better coefficient
  501.             best = check;
  502.             bestCoefficient = coefficient;
  503.         }
  504.     }
  505.  
  506.     return best;
  507. };
  508.  
  509. BotPlayer.prototype.shortestPrey = function(cell, list) {
  510.     // Finds the shortest prey to target
  511.     if (list.length == 0) return null; // List is empty
  512.  
  513.     var distances = [];
  514.     var indexes = [];
  515.  
  516.     for (var i = 1; i < list.length; i++) {
  517.         var check = list[i];
  518.         distances.push([this.distance(cell, check), check]);
  519.     }
  520.  
  521.     distances.sort(function(a, b) {
  522.         return b[0] - a[0];
  523.     });
  524.  
  525.     return distances[0][1];
  526. };
  527.  
  528. BotPlayer.prototype.getBiggest = function(list) {
  529.     // Gets the biggest cell from the array
  530.     var biggest = list[0];
  531.     for (var i = 1; i < list.length; i++) {
  532.         var check = list[i];
  533.         if (check.mass > biggest.mass) {
  534.             biggest = check;
  535.         }
  536.     }
  537.  
  538.     return biggest;
  539. };
  540.  
  541. BotPlayer.prototype.distance = function(position1, position2) {
  542.     var xs = position1.x - position2.x;
  543.     var ys = position1.y - position2.y;
  544.     return Math.sqrt(xs * xs + ys * ys);
  545. };
  546.  
  547. BotPlayer.prototype.angle = function(position1, position2) {
  548.     var xs = position1.x - position2.x;
  549.     var ys = position1.y - position2.y;
  550.     return Math.atan2(xs, ys);
  551. };
  552.  
  553. BotPlayer.prototype.edgeDistance = function(cell, check) {
  554.     // distance - (r1 + r2)
  555.     return this.distance(cell.position, check.position) - this.collideDistance(cell, check);
  556. };
  557.  
  558. BotPlayer.prototype.isVirus = function(cell) {
  559.     return cell.spiked == 1;
  560. };
  561.  
  562. BotPlayer.prototype.collideDistance = function(cell, check) {
  563.     // r1 + r2
  564.     return cell.getSize() + check.getSize();
  565. };
  566.  
  567. BotPlayer.prototype.isMyTeam = function(check) {
  568.     // Is that cell in my team?
  569.     return this.team == check.owner.team && this.gameServer.gameMode.haveTeams;
  570. };
  571.  
  572. BotPlayer.prototype.canSplitkill = function(cell, check) {
  573.     // Can I split to eat this cell?
  574.     var dist = this.distance(cell.position, check.position);
  575.     var splitDist = this.splitDistance(cell);
  576.     return (cell.mass / 2.6) > check.mass && dist < splitDist;
  577. };
  578.  
  579. BotPlayer.prototype.splitDistance = function(cell) {
  580.     // How long will I go after I have split
  581.     var mass = cell.mass;
  582.     var t = Math.PI * Math.PI;
  583.     var modifier = 3 + Math.log(1 + mass) / 10;
  584.     var splitSpeed = this.gameServer.config.playerSpeed * Math.min(Math.pow(mass, -Math.PI / t / 10) * modifier, 150);
  585.     return Math.max(splitSpeed * 6.8, cell.getSize() * 2); // Checked via C#, final distance is near 6.512x splitSpeed
  586. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement