Skip to content

Instantly share code, notes, and snippets.

@chrahunt
Created February 21, 2015 02:36
Show Gist options
  • Save chrahunt/67d6e4517f32e148198f to your computer and use it in GitHub Desktop.
Save chrahunt/67d6e4517f32e148198f to your computer and use it in GitHub Desktop.
Example Offense Bot that makes use of tagpro-navmesh library.
// ==UserScript==
// @name TagPro Example Offense Bot
// @description Limited example offense bot for TagPro.
// @version 0.1
// @grant none
// @include http://tagpro-maptest.koalabeast.com:*
// @include http://tangent.jukejuice.com:*
// @include http://*.newcompte.fr:*
// @author snaps_
// @namespace http://www.reddit.com/user/snaps_
// @license MIT
// @require https://raw.githubusercontent.com/chrahunt/tagpro-navmesh/master/build/navmesh.min.js
// @require https://raw.githubusercontent.com/enoex/Bragi-Browser/master/dist/bragi.min.js
// ==/UserScript==
var Logger = BRAGI;
/*
* This function will execute the provided function after tagpro.playerId
* has been assigned.
*/
function waitForInitialized(fn) {
// Don't execute the function until tagpro.playerId has been assigned.
if (!tagpro || !tagpro.playerId || !tagpro.map) {
return setTimeout(function() {
waitForInitialized(fn)
}, 100);
} else {
// Only run the script if we are not spectating.
if (!tagpro.spectator) {
fn();
}
}
}
// Note: There is LOTS OF pathfinding.
var Bot = function(map, logger) {
this.logger = logger;
this.navmesh = new NavMesh(map, this.logger);
// Set navmesh to listen for mapupdates.
this.navmesh.listen(tagpro.socket);
this.self = tagpro.players[tagpro.playerId];
this.state = {
flag: false
};
this.intervals = {};
this.navmesh.onInit(function() {
this.init();
}.bind(this));
};
// Initialize the bot.
Bot.prototype.init = function() {
this.logger.log("bot", "Initializing.");
this.updating = false;
this.needUpdate = true;
this.path = false;
this.intervals.update = setInterval(this.update.bind(this), 20);
this.intervals.seek = setInterval(this.seek.bind(this), 20);
this.intervals.sense = setInterval(this.sense.bind(this), 20);
this.intervals.updatePath = setInterval(this.updatePath.bind(this), 500);
};
/*
* Stop the bot. If stopUpdate is true, then the bot will stop completely.
* You can stop the bot from the console using
* myBot.stop(true);
*/
Bot.prototype.stop = function(stopUpdate) {
if (typeof stopUpdate == 'undefined') stopUpdate = false;
for (var i in this.intervals) {
if (!stopUpdate && i == 'update') {
continue;
}
clearInterval(this.intervals[i]);
}
};
// Seek to the currently defined target.
Bot.prototype.seek = function() {
if (!this.target) return;
this.logger.log("bot:debug", "Seeking target.");
var seek = {};
seek.x = this.target.x - (this.self.x + this.self.vx);
seek.y = this.target.y - (this.self.y + this.self.vy);
this.move(seek);
};
// Sense situations that warrant an update.
Bot.prototype.sense = function() {
if (this.state.flag !== this.self.flag) {
this.needUpdate = true;
this.state.flag = this.self.flag;
}
};
// The brains.
Bot.prototype.update = function() {
// Stop if dead or game not active.
if (this.self.dead || tagpro.state !== 1) {
this.stop();
return;
}
if (!this.updating && (this.needUpdate || !this.path)) {
this.logger.log("Needed update", this.needUpdate, this.path);
this.needUpdate = false;
this.updating = true;
var flag = null;
if (this.self.team == 1) {
if (!this.self.flag) {
flag = Util.findFlag('blue');
} else {
flag = Util.findFlag('red');
}
} else {
if (!this.self.flag) {
flag = Util.findFlag('red');
} else {
flag = Util.findFlag('blue');
}
}
var start = {
x: this.self.x,
y: this.self.y
};
this.navmesh.calculatePath(start, flag, function(path) {
if (path && path.length > 1) {
// Remove the current location from the path.
this.path = path.slice(1);
// Set the target.
this.target = path[0];
} else {
this.logger.log("Bot", "No path found!");
this.path = null;
}
this.updating = false;
}.bind(this));
} else {
// Nothing to do except wait!
}
};
// Update the path to our destination point based on the furthest-visible point along the path.
Bot.prototype.updatePath = function() {
if (!this.path) return;
// Assuming we have a path.
// Get player position.
var position = {
x: this.self.x,
y: this.self.y
};
var path = this.path;
var noneVisible = true;
var furthestVisible = 0;
for (var i = 0; i < path.length; i++) {
var point = path[i];
if (this.navmesh.checkVisible(position, point)) {
this.logger.log("bot:debug", "Point visible.");
noneVisible = false;
furthestVisible = i;
} else {
this.logger.log("bot:debug", "Not visible.");
}
}
this.logger.log("bot:debug", "None visible:", noneVisible);
this.logger.log("bot:debug", "Furthest visible:", i);
if (noneVisible) {
this.logger.log("bot:debug", "None visible.");
// Set flag so we recalculate path.
this.needUpdate = true;
} else if (furthestVisible !== 0) {
// Update path.
this.path = path.slice(furthestVisible);
this.logger.log("bot:debug", "New path length:", this.path.length);
// Update goal point.
this.target = this.path[0];
}
};
/**
* Sends key events to move to a destination.
* @param {point} destination - The destination relative to the bot.
*/
Bot.prototype.move = function(destination) {
if (destination.x > 1) {
tagpro.sendKeyPress("left", true);
tagpro.sendKeyPress("right", false);
} else if (destination.x < -1) {
tagpro.sendKeyPress("right", true);
tagpro.sendKeyPress("left", false);
} else {
tagpro.sendKeyPress("right", true);
tagpro.sendKeyPress("left", true);
}
if (destination.y > 1) {
tagpro.sendKeyPress("up", true);
tagpro.sendKeyPress("down", false);
} else if (destination.y < -1) {
tagpro.sendKeyPress("down", true);
tagpro.sendKeyPress("up", false);
} else {
tagpro.sendKeyPress("up", true);
tagpro.sendKeyPress("down", true);
}
}
var Util = {};
// Returns the position (in pixels) of the flag.
// Color is a string, one of either: 'red', 'blue', or 'yellow'.
Util.findFlag = function(color) {
for (var x = 0, xl = tagpro.map.length, yl = tagpro.map[0].length; x < xl; x++) {
for (var y = 0; y < yl; y++) {
switch (Math.floor(tagpro.map[x][y])) {
case 3:
if (color === 'red')
return {x: x * 40, y: y * 40};
break;
case 4:
if (color === 'blue')
return {x: x * 40, y: y * 40};
break;
case 16:
if (color === 'yellow')
return {x: x * 40, y: y * 40};
break;
}
}
}
}
// Override functions to help gather informatoin.
Util.overrides = function() {
// Overriding this function to get a more accurate velocity of players.
// Velocity is saved in player.vx and vy.
Box2D.Dynamics.b2Body.prototype.GetLinearVelocity = function() {
tagpro.players[this.player.id].vx = this.m_linearVelocity.x * 55;
tagpro.players[this.player.id].vy = this.m_linearVelocity.y * 55;
return this.m_linearVelocity;
};
};
// Initialize the script when tagpro is ready, and additionally wait
// for the relevant properties to be assigned.
tagpro.ready(function() {
waitForInitialized(function() {
window.myBot = new Bot(tagpro.map, Logger);
Util.overrides();
});
});
@grandwarcc
Copy link

Hey, im new to this, what does this bot do?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment