Skip to content

Instantly share code, notes, and snippets.

@iczero
Last active November 30, 2018 20:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iczero/e81ea3811ca5c4f72e2afad55b3891fd to your computer and use it in GitHub Desktop.
Save iczero/e81ea3811ca5c4f72e2afad55b3891fd to your computer and use it in GitHub Desktop.
const SELECTOR = '.zr_zergling_container';
/**
* Fire a mouse event on an element
* @param {Element} node
* @param {String} type
*/
function triggerMouseEvent(node, type) {
let event = document.createEvent('MouseEvent');
event.initEvent(type, true, true);
node.dispatchEvent(event);
}
/**
* Get nearest point of an element, also stolen from stackoverflow
* @param {Object} from From point
* @param {Object} to To point
* @param {Object} boxSize Box size
* @return {Object}
*/
function getNearestPointOutside(from, to, boxSize) {
// which side does it hit?
// get the angle of to from from.
let theta = Math.atan2(boxSize.y, boxSize.x);
let phi = Math.atan2(to.y - from.y, to.x - from.x);
let nearestPoint = {};
if (Math.abs(phi) < theta) { // crosses +x
nearestPoint.x = from.x + boxSize.x / 2.0;
nearestPoint.y = from.y + ((to.x === from.x) ? from.y :
((to.y - from.y) / (to.x - from.x) * boxSize.x / 2.0));
} else if (Math.PI - Math.abs(phi) < theta) { // crosses -x
nearestPoint.x = from.x - boxSize.x / 2.0;
nearestPoint.y = from.y + ((to.x === from.x) ? from.y :
(-(to.y - from.y) / (to.x - from.x) * boxSize.x / 2.0));
} else if (to.y > from.y) { // crosses +y
nearestPoint.y = from.y + boxSize.y / 2.0;
nearestPoint.x = from.x + ((to.y === from.y) ? 0 :
((to.x - from.x) / (to.y - from.y) * boxSize.y / 2.0));
} else { // crosses -y
nearestPoint.y = from.y - boxSize.y / 2.0;
nearestPoint.x = from.x - ((to.y === from.y) ? 0 :
((to.x - from.x) / (to.y - from.y) * boxSize.y / 2.0));
}
return nearestPoint;
}
/** A Zerg turret */
class ZergTurret {
/**
* Start the thing
* @param {Number} speed How fast the turret shoots
* @param {Object} turret x, y location of turret
*/
constructor(speed, turret) {
this.speed = speed;
this.turret = turret;
this.elements = this.target(SELECTOR);
this.lineElem = null;
this.started = false;
}
/** Start targetting */
start() {
if (this.started) return;
this.intervalHandler = () => {
let next = this.elements.next();
if (next.done) return clearInterval(this.interval);
this.runTargeting();
};
this.interval = setInterval(this.intervalHandler, this.speed);
this.started = true;
}
/** Stop targetting */
stop() {
if (!this.started) return;
clearInterval(this.interval);
if (this.lineElem) {
document.body.removeChild(this.lineElem);
this.lineElem = null;
}
this.started = false;
}
/**
* Iterate over elements until no more exist
*/
* target() {
for (;;) {
let elements;
do {
elements = document.querySelectorAll(SELECTOR);
for (let element of elements) {
while (document.body.contains(element)) yield element;
}
} while (elements.length);
yield false;
}
}
/**
* Stolen from stackoverflow, draws lines
* @param {Object} toXY { x, y }
*/
drawLine(toXY) {
if (!this.lineElem) {
this.lineElem = document.createElement('canvas');
this.lineElem.style.position = 'absolute';
this.lineElem.style.zIndex = 1000;
/*
let duration = (this.speed / 1000).toString() + 's';
this.lineElem.style.transition = [
'width', 'height', 'left', 'top'
].map(prop => `${prop} ${duration}`).join(', ');
*/
document.body.appendChild(this.lineElem);
}
let leftpoint;
let rightpoint;
if (this.turret.x < toXY.x) {
leftpoint = this.turret;
rightpoint = toXY;
} else {
leftpoint = toXY;
rightpoint = this.turret;
}
let lineWidthPix = 4;
let gutterPix = 10;
let origin = { x: leftpoint.x - gutterPix,
y: Math.min(this.turret.y, toXY.y) - gutterPix };
this.lineElem.width = Math.max(rightpoint.x - leftpoint.x, lineWidthPix) +
2.0 * gutterPix;
this.lineElem.height = Math.abs(this.turret.y - toXY.y) + 2.0 * gutterPix;
this.lineElem.style.left = origin.x + 'px';
this.lineElem.style.top = origin.y + 'px';
let ctx = this.lineElem.getContext('2d');
// Use the identity matrix while clearing the canvas
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, this.lineElem.width, this.lineElem.height);
ctx.restore();
ctx.lineWidth = 7;
ctx.strokeStyle = '#09f';
ctx.beginPath();
ctx.moveTo(this.turret.x - origin.x, this.turret.y - origin.y);
ctx.lineTo(toXY.x - origin.x, toXY.y - origin.y);
ctx.stroke();
}
/**
* Target and attack a zergling
* @param {Object} this.turret x, y of turret position
* @param {Element} zergling
*/
runTargeting() {
let zergling = this.elements.next().value;
if (!zergling) return;
let bounds = zergling.getBoundingClientRect();
let center = {
x: bounds.left + bounds.width / 2,
y: bounds.top + bounds.height / 2
};
let nearest = getNearestPointOutside(center, this.turret, {
x: bounds.width,
y: bounds.height
});
this.drawLine(nearest);
triggerMouseEvent(zergling, 'mousedown');
}
}
let turret = new ZergTurret(150, { x: 300, y: 300 });
turret.start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment