// ==UserScript==
// @name diepAPI
// @description https://github.com/Cazka/diepAPI
// @version 2.1.1
// @author Cazka
// @match https://diep.io/*
// @icon https://www.google.com/s2/favicons?domain=diep.io
// @namespace https://gf.qytechs.cn/users/541070
// @run-at document-start
// @grant none
// ==/UserScript==
(() => {
if (window.diepAPI) return;
var diepAPI;
/******/ (() => {
// webpackBootstrap
/******/ 'use strict';
/******/ // The require scope
/******/ var __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for (var key in definition) {
/******/ if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/
}
/******/
}
/******/
};
/******/
})();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
/******/
})();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/
}
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/
};
/******/
})();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
CanvasKit: () => /* reexport */ CanvasKit,
Vector: () => /* reexport */ Vector,
arena: () => /* reexport */ arena,
arenaScaling: () => /* reexport */ arenaScaling,
entityManager: () => /* reexport */ entityManager,
game: () => /* reexport */ game,
gamepad: () => /* reexport */ gamepad,
minimap: () => /* reexport */ minimap,
player: () => /* reexport */ player,
}); // CONCATENATED MODULE: ./src/vector.ts
class Vector {
x;
y;
constructor(x, y) {
this.x = x;
this.y = y;
}
/**
* ( u1 ) + ( v1 ) = ( u1 + v1 )
* ( u2 ) ( v2 ) ( u2 + v2 )
*/
static add(u, v) {
return new Vector(u.x + v.x, u.y + v.y);
}
/**
* ( u1 ) - ( v1 ) = ( u1 - v1 )
* ( u2 ) ( v2 ) ( u2 - v2 )
*/
static subtract(u, v) {
return new Vector(u.x - v.x, u.y - v.y);
}
/**
* ( u1 ) * ( v1 ) = ( u1 * v1 )
* ( u2 ) ( v2 ) ( u2 * v2 )
*/
static multiply(u, v) {
return new Vector(u.x * v.x, u.y * v.y);
}
/**
* ( u1 ) / ( v1 ) = ( u1 / v1 )
* ( u2 ) ( v2 ) ( u2 / v2 )
*/
static divide(u, v) {
return new Vector(u.x / v.x, u.y / v.y);
}
/**
* r * ( v1 ) = ( r * v1 )
* ( v2 ) ( r * v2 )
*/
static scale(r, v) {
return new Vector(r * v.x, r * v.y);
}
static round(v) {
return new Vector(Math.round(v.x), Math.round(v.y));
}
static len(v) {
return Math.sqrt(v.x ** 2 + v.y ** 2);
}
static distance(u, v) {
return Vector.len(Vector.subtract(u, v));
}
/**
* Calculates the [centroid](https://en.wikipedia.org/wiki/Centroid)
*/
static centroid(...vertices) {
const sum = vertices.reduce((acc, vec) => Vector.add(acc, vec), new Vector(0, 0));
const centroid = Vector.scale(1 / vertices.length, sum);
return centroid;
}
/**
* Calcutes the radius from a set of vertices that are placed on a circle
*/
static radius(...vertices) {
const centroid = Vector.centroid(...vertices);
const distance = vertices.reduce((acc, vec) => acc + Vector.distance(centroid, vec), 0);
const radius = distance / vertices.length;
return radius;
}
} // CONCATENATED MODULE: ./src/canvas_kit.ts
class CanvasKit {
/**
* The consumer will be called before
*/
static hook(method, consumer) {
const target = window.CanvasRenderingContext2D.prototype;
target[method] = new Proxy(target[method], {
apply(target, thisArg, args) {
if (thisArg.canvas.className !== 'CanvasKit-bypass') consumer(target, thisArg, args);
return Reflect.apply(target, thisArg, args);
},
});
}
/**
* replaces the function. Use `return Reflect.apply(target, thisArg, args);` in
* your function to call the original function.
*/
static replace(method, func) {
const target = window.CanvasRenderingContext2D.prototype;
target[method] = new Proxy(target[method], {
apply(target, thisArg, args) {
if (thisArg.canvas.className !== 'CanvasKit-bypass') return func(target, thisArg, args);
return Reflect.apply(target, thisArg, args);
},
});
}
/**
* The consumer will be called before.
*/
static hookRAF(consumer) {
window.requestAnimationFrame = new Proxy(window.requestAnimationFrame, {
apply(target, thisArg, args) {
consumer();
return Reflect.apply(target, thisArg, args);
},
});
}
/**
* If you want to a canvas then create it with this method.
*/
static createCanvas() {
const canvas = document.createElement('canvas');
canvas.className = 'CanvasKit-bypass';
canvas.style.pointerEvents = 'none';
canvas.style.position = 'fixed';
canvas.style['z-index'] = 1;
canvas.style.top = '0px';
canvas.style.left = '0px';
canvas.style.right = '0px';
canvas.style.bottom = '0px';
canvas.style.width = '100%';
canvas.style.height = '100%';
return canvas;
}
} // CONCATENATED MODULE: ./src/diep_gamepad.ts
class DiepGamepad {
#axes;
#buttons;
connected;
/**
* Emulates a Gampad
* when `gamepad.connected` is set to `true` the game will
* ignore following keyboard inputs:
* W, A, S, D, upArrow, leftArrow, downArrow, rightArray
* leftMouse, rightMouse, Spacebar, Shift,
* MouseMovement to change tank angle
* these are also the only keys we emulate with this gamepad
*
*/
constructor() {
this.#axes = [0, 0, 0, 0];
this.#buttons = [...Array(17)].map((x) => {
return { pressed: false };
});
this.connected = false;
//window.navigator.getGamepads = () => [this.connected ? this.#toGamepad() : undefined];
window.navigator.getGamepads = new Proxy(window.navigator.getGamepads, {
apply: (target, thisArg, args) => {
if (this.connected) return [this.#toGamepad()];
return Reflect.apply(target, thisArg, args);
},
});
}
set x(value) {
this.#axes[0] = value;
}
set y(value) {
this.#axes[1] = value;
}
set mx(value) {
this.#axes[2] = value;
}
set my(value) {
this.#axes[3] = value;
}
set leftMouse(value) {
this.#buttons[7].pressed = value;
}
set rightMouse(value) {
this.#buttons[6].pressed = value;
}
get x() {
return this.#axes[0];
}
get y() {
return this.#axes[1];
}
get mx() {
return this.#axes[2];
}
get my() {
return this.#axes[3];
}
get leftMouse() {
return this.#buttons[7].pressed;
}
get rightMouse() {
return this.#buttons[6].pressed;
}
#toGamepad() {
return {
axes: this.#axes,
buttons: this.#buttons,
mapping: 'standard',
};
}
}
const gamepad = new DiepGamepad(); // CONCATENATED MODULE: ./src/event_emitter.ts
class EventEmitter extends EventTarget {
/**
*
* @param {string} eventName The name of the event
* @param {...any} args The arguments that will be passed to the listener
*/
emit(eventName, ...args) {
this.dispatchEvent(new CustomEvent(eventName, { detail: args }));
}
/**
*
* @param {string} eventName The name of the event
* @param {EventCallback} listener The callback function
*/
on(eventName, listener) {
this.addEventListener(eventName, (e) => Reflect.apply(listener, this, e.detail));
}
/**
*
* @param {string} eventName The name of the event
* @param {EventCallback} listener The callback function
*/
once(eventName, listener) {
this.addEventListener(eventName, (e) => Reflect.apply(listener, this, e.detail), { once: true });
}
/**
*
* @param {string} eventName The name of the event
* @param {EventCallback} listener The callback function
*/
off(eventName, listener) {
this.removeEventListener(eventName, listener);
}
} // CONCATENATED MODULE: ./src/game.ts
class Game extends EventEmitter {
#ready = false;
constructor() {
super();
CanvasKit.hookRAF(() => this.#onframe());
}
#onframe() {
if (!this.#ready && window.input !== undefined) {
this.#ready = true;
this.#onready();
}
super.emit('frame');
}
#onready() {
setTimeout(() => super.emit('ready'), 100);
}
}
const game = new Game(); // CONCATENATED MODULE: ./src/minimap.ts
class Minimap {
#minimapDim = new Vector(1, 1);
#minimapPos = new Vector(0, 0);
#viewportDim = new Vector(1, 1);
#viewportPos = new Vector(0, 0);
/**
* @description The position of the arrow normalized to the range [0,1]
*/
#arrowPos = new Vector(0.5, 0.5);
#drawViewport = false;
constructor() {
game.once('ready', () => {
window.input.set_convar('ren_minimap_viewport', 'true');
window.input.set_convar = new Proxy(window.input.set_convar, {
apply: (target, thisArg, args) => {
if (args[0] === 'ren_minimap_viewport') this.#drawViewport = args[1];
else Reflect.apply(target, thisArg, args);
},
});
});
this._minimapHook();
this._viewportHook();
this._arrowHook();
}
get minimapDim() {
return this.#minimapDim;
}
get minimapPos() {
return this.#minimapPos;
}
get viewportDim() {
return this.#viewportDim;
}
get viewportPos() {
return this.#viewportPos;
}
get arrowPos() {
return this.#arrowPos;
}
drawViewport(value) {
this.#drawViewport = value;
}
_minimapHook() {
CanvasKit.hook('strokeRect', (target, thisArg, args) => {
const transform = thisArg.getTransform();
this.#minimapDim = new Vector(transform.a, transform.d);
this.#minimapPos = new Vector(transform.e, transform.f);
});
}
_viewportHook() {
CanvasKit.replace('fillRect', (target, thisArg, args) => {
const transform = thisArg.getTransform();
if (
Math.round((transform.a / transform.d) * 10_000) !==
Math.round((window.innerWidth / window.innerHeight) * 10_000)
) {
return Reflect.apply(target, thisArg, args);
}
if (transform.a >= window.innerWidth && transform.d >= window.innerHeight) {
return Reflect.apply(target, thisArg, args);
}
this.#viewportDim = new Vector(transform.a, transform.d);
this.#viewportPos = new Vector(transform.e, transform.f);
if (this.#drawViewport) return Reflect.apply(target, thisArg, args);
});
}
_arrowHook() {
let index = 0;
let pointA;
let pointB;
let pointC;
const calculatePos = () => {
const side1 = Math.round(Vector.distance(pointA, pointB));
const side2 = Math.round(Vector.distance(pointA, pointC));
const side3 = Math.round(Vector.distance(pointB, pointC));
if (side1 === side2 && side2 === side3) return;
const centroid = Vector.centroid(pointA, pointB, pointC);
const arrowPos = Vector.subtract(centroid, this.#minimapPos);
const position = Vector.divide(arrowPos, this.#minimapDim);
this.#arrowPos = position;
};
CanvasKit.hook('beginPath', (target, thisArg, args) => {
index = 1;
});
CanvasKit.hook('moveTo', (target, thisArg, args) => {
if (index === 1) {
index++;
pointA = new Vector(args[0], args[1]);
return;
}
index = 0;
});
CanvasKit.hook('lineTo', (target, thisArg, args) => {
if (index === 2) {
index++;
pointB = new Vector(args[0], args[1]);
return;
}
if (index === 3) {
index++;
pointC = new Vector(args[0], args[1]);
return;
}
index = 0;
});
CanvasKit.hook('fill', (target, thisArg, args) => {
if (index === 4) {
index++;
calculatePos();
return;
}
index = 0;
});
}
}
const minimap = new Minimap(); // CONCATENATED MODULE: ./src/camera.ts
class Camera {
get position() {
const center = Vector.add(minimap.viewportPos, Vector.scale(0.5, minimap.viewportDim));
const cameraPos = Vector.subtract(center, minimap.minimapPos);
const normalized = Vector.divide(cameraPos, minimap.minimapDim);
return arena.scale(normalized);
}
}
const camera = new Camera(); // CONCATENATED MODULE: ./src/arena_scaling.ts
class ArenaScaling {
#scalingFactor = 1;
constructor() {
CanvasKit.hook('stroke', (target, thisArg, args) => {
if (thisArg.fillStyle === '#cdcdcd' && thisArg.globalAlpha !== 0) {
this.#scalingFactor = thisArg.globalAlpha * 10;
}
});
}
get scalingFactor() {
return this.#scalingFactor;
}
get windowRatio() {
return Math.max(window.innerWidth / 1920, window.innerHeight / 1080);
}
get fov() {
return this.#scalingFactor / this.windowRatio;
}
/**
*
* @param {Vector} v The vector in canvas units
* @returns {Vector} The vector in arena units
*/
toArenaUnits(v) {
return Vector.scale(1 / this.#scalingFactor, v);
}
/**
*
* @param {Vector} v The vector in arena units
* @returns {Vector} The vector in canvas units
*/
toCanvasUnits(v) {
return Vector.scale(this.#scalingFactor, v);
}
/**
* Will translate coordinates from canvas to arena
* @param {Vector} canvasPos The canvas coordinates
* @returns {Vector} The `canvasPos` translated to arena coordinates
*/
toArenaPos(canvasPos) {
const direction = Vector.subtract(
canvasPos,
this.screenToCanvas(new Vector(window.innerWidth / 2, window.innerHeight / 2))
);
const scaled = this.toArenaUnits(direction);
const arenaPos = Vector.add(scaled, camera.position);
return arenaPos;
}
/**
* Will translate coordinates from arena to canvas
* @param {Vector} arenaPos The arena coordinates
* @returns {Vector} The `arenaPos` translated to canvas coordinates
*/
toCanvasPos(arenaPos) {
const direction = Vector.subtract(arenaPos, camera.position);
const scaled = this.toCanvasUnits(direction);
const canvasPos = Vector.add(
scaled,
this.screenToCanvas(new Vector(window.innerWidth / 2, window.innerHeight / 2))
);
return canvasPos;
}
screenToCanvasUnits(n) {
return n * window.devicePixelRatio;
}
canvasToScreenUnits(n) {
return n / window.devicePixelRatio;
}
/**
* Will translate coordinates from screen to canvas
* @param v The screen coordinates
* @returns The canvas coordinates
*/
screenToCanvas(v) {
return Vector.scale(window.devicePixelRatio, v);
}
/**
* Will translate coordinates from canvas to screen
* @param v The canvas coordinates
* @returns the screen coordinates
*/
canvasToScreen(v) {
return Vector.scale(1 / window.devicePixelRatio, v);
}
}
const arenaScaling = new ArenaScaling(); // CONCATENATED MODULE: ./src/arena.ts
class Arena {
#size = 1;
constructor() {
game.on('frame', () => {
const ratio = Vector.divide(minimap.minimapDim, minimap.viewportDim);
const arenaDim = Vector.multiply(
ratio,
arenaScaling.screenToCanvas(new Vector(window.innerWidth, window.innerHeight))
);
const arenaSize = Vector.round(arenaScaling.toArenaUnits(arenaDim));
this.#size = arenaSize.x;
});
}
/**
* @returns {number} The Arena size in arena units
*/
get size() {
return this.#size;
}
//These methods are not much used. can be moved to playerMovement.mjs where its currently only used.
/**
*
* @param {Vector} vector The vector in [0, 1] coordinates
* @returns {Vector} The scaled vector in [-Arena.size/2, Arena.size/2] coordinates
*/
scale(vector) {
const scale = (value) => Math.round(this.#size * (value - 0.5));
return new Vector(scale(vector.x), scale(vector.y));
}
/**
*
* @param {Vector} vector - The scaled vector in [-Arena.size/2, Arena.size/2] coordinates
* @returns {Vector} The unscaled vector in [0, 1] coordinates
*/
unscale(vector) {
const unscale = (value) => value / this.#size + 0.5;
return new Vector(unscale(vector.x), unscale(vector.y));
}
}
const arena = new Arena(); // CONCATENATED MODULE: ./src/movement.ts
class Movement {
#position = new Vector(0, 0);
#velocity = new Vector(0, 0);
/*
* used for average velocity calculation
*/
#velocitySamplesSize = 10;
#velocitySamples = [];
#velocitySamplesIndex = 0;
#velocityLastNow = performance.now();
get position() {
return this.#position;
}
/**
* Velocity in [diep_]units / second
*/
get velocity() {
return this.#velocity;
}
/**
* Predict where this object will be after `time`
* @param time The time in ms.
*/
predictPos(time) {
const duration = (time + performance.now() - this.#velocityLastNow) / 1000;
return Vector.add(this.#position, Vector.scale(duration, this.#velocity));
}
updatePos(newPos) {
this.#updateVelocity(newPos);
this.#position = newPos;
}
#updateVelocity(newPos) {
const now = performance.now();
const time = (now - this.#velocityLastNow) / 1000;
if (time === 0) return;
this.#velocityLastNow = now;
const velocity = Vector.scale(1 / time, Vector.subtract(newPos, this.#position));
// add current velocity to our samples array
this.#velocitySamples[this.#velocitySamplesIndex++] = velocity;
this.#velocitySamplesIndex %= this.#velocitySamplesSize;
// calculate the average velocity
this.#velocity = Vector.scale(
1 / this.#velocitySamples.length,
this.#velocitySamples.reduce((acc, x) => Vector.add(acc, x))
);
}
} // CONCATENATED MODULE: ./src/player_movement.ts
class PlayerMovement extends Movement {
/**
* Using the minimap arrow to get the player position and velocity
*/
constructor() {
super();
game.on('frame', () => super.updatePos(arena.scale(minimap.arrowPos)));
}
}
const playerMovement = new PlayerMovement(); // CONCATENATED MODULE: ./src/player.ts
const sleep = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));
class Player extends EventEmitter {
#isDead = true;
#mouseLock = false;
#mouseCanvasPos = new Vector(0, 0);
#mousePos = new Vector(0, 0);
#gamemode = window.localStorage.gamemode;
#level = 1;
#tank = 'Tank';
constructor() {
super();
game.once('ready', () => {
//Check dead or alive
game.on('frame', () => {
const isDead = !window.input.should_prevent_unload();
if (this.#isDead == isDead) return;
this.#isDead = isDead;
if (this.#isDead) this.#ondead();
else this.#onspawn();
});
//update mouse position
game.on('frame', () => {
this.#mousePos = arenaScaling.toArenaPos(this.#mouseCanvasPos);
});
//Mouse events
const canvas = document.getElementById('canvas');
canvas.onmousemove = new Proxy(canvas.onmousemove, {
apply: (target, thisArg, args) => {
if (this.#mouseLock) return;
this.#onmousemove(args[0]);
return Reflect.apply(target, thisArg, args);
},
});
canvas.onmousedown = new Proxy(canvas.onmousedown, {
apply: (target, thisArg, args) => {
if (this.#mouseLock) return;
this.#onmousedown(args[0]);
return Reflect.apply(target, thisArg, args);
},
});
canvas.onmouseup = new Proxy(canvas.onmouseup, {
apply: (target, thisArg, args) => {
if (this.#mouseLock) return;
this.#onmouseup(args[0]);
return Reflect.apply(target, thisArg, args);
},
});
//Key events
window.onkeydown = new Proxy(window.onkeydown, {
apply: (target, thisArg, args) => {
this.#onkeydown(args[0]);
return Reflect.apply(target, thisArg, args);
},
});
window.onkeyup = new Proxy(window.onkeyup, {
apply: (target, thisArg, args) => {
this.#onkeyup(args[0]);
return Reflect.apply(target, thisArg, args);
},
});
// tank and level event listener
CanvasKit.hook('fillText', (target, thisArg, args) => {
const text = args[0];
const match = text.match(/^Lvl (\d+) (\w*)$/);
if (match == null) {
return;
}
const newLevel = Number(match[1]);
const newTank = match[2];
// make sure to trigger events for all levels in between.
while (newLevel > this.#level + 1) {
super.emit('level', ++this.#level);
}
if (newLevel !== this.#level) super.emit('level', newLevel);
if (newTank !== this.#tank) super.emit('tank', newTank);
this.#level = newLevel;
this.#tank = match[2];
});
});
}
get position() {
return playerMovement.position;
}
get velocity() {
return playerMovement.velocity;
}
get mouse() {
return this.#mousePos;
}
get isDead() {
return this.#isDead;
}
get gamemode() {
return this.#gamemode;
}
get level() {
return this.#level;
}
get tank() {
return this.#tank;
}
/**
* Predict where this object will be after `time`
* @param time The time in ms
*/
predictPos(time) {
return playerMovement.predictPos(time);
}
/**
* Fun function to upgrade to octo
* @async
*/
async octoBuild() {
this.keyDown('k');
await this.upgrade_stat(4, 7);
await this.upgrade_stat(5, 7);
await this.upgrade_stat(6, 7);
await this.upgrade_stat(7, 7);
await this.upgrade_stat(8, 5);
await this.upgrade_tank(1);
await this.upgrade_tank(2);
await this.upgrade_tank(1);
this.keyUp('k');
}
async #ondead() {
await sleep(50);
super.emit('dead');
}
async #onspawn() {
this.#gamemode = window.localStorage.gamemode;
await sleep(50);
super.emit('spawn');
}
useGamepad(value) {
gamepad.connected = value;
}
keyDown(key) {
if (typeof key == 'string') {
if (key.length != 1) throw new Error(`diepAPI: Unsupported key: ${key}`);
key = key.toUpperCase().charCodeAt(0);
}
window.input.keyDown(key);
this.#onkeydown({ keyCode: key });
}
keyUp(key) {
if (typeof key == 'string') {
if (key.length != 1) throw new Error(`diepAPI: Unsupported key: ${key}`);
key = key.toUpperCase().charCodeAt(0);
}
window.input.keyUp(key);
this.#onkeyup({ keyCode: key });
}
async keyPress(key) {
this.keyDown(key);
await sleep(200);
this.keyUp(key);
await sleep(10);
}
async spawn(name, attempts = 0) {
if (!this.#isDead) return;
if (name !== undefined) document.getElementById('textInput').value = name;
await this.keyPress(13);
await sleep(250);
await this.spawn(name, attempts + 1);
}
async upgrade_stat(id, level) {
if (id < 1 || id > 8) throw `diepAPI: ${id} is not a supported stat`;
this.keyDown(85);
for (let i = 0; i < level; i++) {
await this.keyPress(48 + id);
}
this.keyUp(85);
await sleep(250);
}
async upgrade_tank(index) {
index -= 1;
const x_index = index % 2;
const y_index = Math.floor(index / 2);
const x = arenaScaling.screenToCanvasUnits(arenaScaling.windowRatio * (x_index * 115 + 97.5));
const y = arenaScaling.screenToCanvasUnits(arenaScaling.windowRatio * (y_index * 110 + 120));
this.#mouseLock = true;
window.input.mouse(x, y);
await this.keyPress(1);
// wait 200 ms before disabling mouselock
await sleep(200);
this.#mouseLock = false;
// wait 1500 ms for the animation to finish
await sleep(1500);
}
moveTo(arenaPos) {
if (gamepad.connected) {
const direction = Vector.subtract(arenaPos, this.position);
const distance = Vector.len(direction);
if (distance === 0) {
gamepad.x = 0;
gamepad.y = 0;
return;
}
//max speed
const velocity = Vector.scale(1 / distance, direction);
gamepad.x = velocity.x;
gamepad.y = velocity.y;
} else {
const direction = Vector.subtract(arenaPos, this.position);
if (direction.x > 0) {
this.keyUp('a');
this.keyDown('d');
} else if (direction.x < 0) {
this.keyUp('d');
this.keyDown('a');
} else {
this.keyUp('a');
this.keyUp('d');
}
if (direction.y > 0) {
this.keyUp('w');
this.keyDown('s');
} else if (direction.y < 0) {
this.keyUp('s');
this.keyDown('w');
} else {
this.keyUp('w');
this.keyUp('s');
}
}
}
lookAt(arenaPos) {
const position = arenaScaling.toCanvasPos(arenaPos);
window.input.mouse(position.x, position.y);
this.#onmousemove({ clientX: position.x, clientY: position.y });
}
#onmousemove(e) {
this.#mouseCanvasPos = arenaScaling.screenToCanvas(new Vector(e.clientX, e.clientY));
if (gamepad.connected) {
const arenaPos = arenaScaling.toArenaPos(this.#mouseCanvasPos);
const direction = Vector.subtract(arenaPos, this.position);
let axes = Vector.scale(arenaScaling.fov / 1200 / 1.1, direction);
const length = Vector.len(axes);
if (length !== 0 && length < 0.15) {
axes = Vector.scale(0.15 / length, axes);
}
gamepad.mx = axes.x;
gamepad.my = axes.y;
}
}
#onmousedown(e) {
if (gamepad.connected) this.#onkeydown({ keyCode: e.which });
}
#onmouseup(e) {
if (gamepad.connected) this.#onkeyup({ keyCode: e.which });
}
#onkeydown(e) {
super.emit('keydown', e.keyCode);
if (gamepad.connected) {
switch (e.keyCode) {
case 37:
case 65:
gamepad.x = -1;
break;
case 40:
case 83:
gamepad.y = 1;
break;
case 38:
case 87:
gamepad.y = -1;
break;
case 39:
case 68:
gamepad.x = 1;
break;
case 1:
case 32:
gamepad.leftMouse = true;
break;
case 3:
case 16:
gamepad.rightMouse = true;
break;
}
}
}
#onkeyup(e) {
super.emit('keyup', e.keyCode);
if (gamepad.connected) {
switch (e.keyCode) {
case 37:
case 65:
gamepad.x = 0;
break;
case 40:
case 83:
gamepad.y = 0;
break;
case 38:
case 87:
gamepad.y = 0;
break;
case 39:
case 68:
gamepad.x = 0;
break;
case 1:
case 32:
gamepad.leftMouse = false;
break;
case 3:
case 16:
gamepad.rightMouse = false;
break;
}
}
}
}
const player = new Player(); // CONCATENATED MODULE: ./src/entity.ts
var EntityType;
(function (EntityType) {
EntityType[(EntityType['Player'] = 0)] = 'Player';
EntityType[(EntityType['Bullet'] = 1)] = 'Bullet';
EntityType[(EntityType['Drone'] = 2)] = 'Drone';
EntityType[(EntityType['Trap'] = 3)] = 'Trap';
EntityType[(EntityType['Square'] = 4)] = 'Square';
EntityType[(EntityType['Triangle'] = 5)] = 'Triangle';
EntityType[(EntityType['Pentagon'] = 6)] = 'Pentagon';
EntityType[(EntityType['AlphaPentagon'] = 7)] = 'AlphaPentagon';
EntityType[(EntityType['Crasher'] = 8)] = 'Crasher';
EntityType[(EntityType['UNKNOWN'] = 9)] = 'UNKNOWN';
})(EntityType || (EntityType = {}));
var EntityColor;
(function (EntityColor) {
EntityColor['TeamBlue'] = '#00b2e1';
EntityColor['TeamRed'] = '#f14e54';
EntityColor['TeamPurple'] = '#bf7ff5';
EntityColor['TeamGreen'] = '#00e16e';
EntityColor['Square'] = '#ffe869';
EntityColor['Triangle'] = '#fc7677';
EntityColor['Pentagon'] = '#768dfc';
EntityColor['AlphaPentagon'] = '#768dfc';
EntityColor['Crasher'] = '#f177dd';
EntityColor['NecromancerDrone'] = '#fcc376';
})(EntityColor || (EntityColor = {}));
const TeamColors = [EntityColor.TeamBlue, EntityColor.TeamRed, EntityColor.TeamPurple, EntityColor.TeamGreen];
/**
* Represents an ingame Entity.
*
* Holds minimal information currently.
*/
class Entity extends Movement {
type;
extras;
constructor(type, extras = {}) {
super();
this.type = type;
this.extras = extras;
}
updatePos(newPos) {
super.updatePos(newPos);
}
} // CONCATENATED MODULE: ./src/entity_manager.ts
/**
* Entity Manager is used to access the information about the entities, that are currently drawn on the screen.
* To access the entities the EntityManager exposes the EntityManager.entities field.
*/
class EntityManager {
#entities = [];
#entitiesUpdated = [];
constructor() {
this.#triangleHook();
this.#squareHook();
this.#pentagonHook();
//when is a bullet being drawn?
//when is a player being drawn?
this.#playerHook();
game.on('frame', () => {
this.#entities = this.#entitiesUpdated;
this.#entitiesUpdated = [];
});
}
get entities() {
return this.#entities;
}
/**
* Adds the entity to `#entitiesUpdated`.
*
* Will either find the entity in `#entities` or create a new `Entity`.
*/
#add(type, position, extras = {}) {
const entityIndex = this.#findEntity(type, position);
let entity;
if (entityIndex === -1) {
entity = new Entity(type, {
id: Math.random().toString(36).slice(2, 5),
timestamp: performance.now(),
...extras,
});
} else {
entity = this.#entities[entityIndex];
}
entity.updatePos(position);
this.#entitiesUpdated.push(entity);
}
/**
* Searches `#entities` for the entity that is closest to `position` and
* returns the __index__ of that entity or __-1__ if there is no match.
*/
#findEntity(type, position) {
let result = -1;
let shortestDistance = Number.MAX_SAFE_INTEGER;
this.#entities.forEach((x, i) => {
const distance = Vector.distance(x.predictPos(0), position);
if (distance < shortestDistance) {
shortestDistance = distance;
result = i;
}
});
//if distance is too high
if (shortestDistance > 28 /* accuracy */) {
return -1;
}
//sanity check
if (EntityType.UNKNOWN !== type && this.#entities[result].type !== type) {
return -1;
}
return result;
}
/**
* Will call the cb method, when a polygon with `numVertices` vertices is drawn.
*/
#createPolygonHook(numVertices, cb) {
let index = 0;
let vertices = [];
const onFillPolygon = (ctx) => {
cb(vertices, ctx);
};
CanvasKit.hook('beginPath', (target, thisArg, args) => {
index = 1;
vertices = [];
});
CanvasKit.hook('moveTo', (target, thisArg, args) => {
if (index === 1) {
index++;
vertices.push(new Vector(args[0], args[1]));
return;
}
index = 0;
});
CanvasKit.hook('lineTo', (target, thisArg, args) => {
if (index >= 2 && index <= numVertices) {
index++;
vertices.push(new Vector(args[0], args[1]));
return;
}
index = 0;
});
CanvasKit.hook('fill', (target, thisArg, args) => {
if (index === numVertices + 1) {
index++;
onFillPolygon(thisArg);
return;
}
index = 0;
});
}
#triangleHook() {
this.#createPolygonHook(3, (vertices, ctx) => {
const side1 = Math.round(Vector.distance(vertices[0], vertices[1]));
const side2 = Math.round(Vector.distance(vertices[0], vertices[2]));
const side3 = Math.round(Vector.distance(vertices[1], vertices[2]));
//ignore Minimap Arrow
if (side1 !== side2 || side2 !== side3) return;
//ignore Leader Arrow
if ('#000000' === ctx.fillStyle) return;
vertices = vertices.map((x) => arenaScaling.toArenaPos(x));
const position = Vector.centroid(...vertices);
const radius = Math.round(Vector.radius(...vertices));
const color = ctx.fillStyle;
let type;
switch (radius) {
case 23:
//battleship drone
if (TeamColors.includes(color)) type = EntityType.Drone;
break;
case 30:
//base drone
if (TeamColors.includes(color)) type = EntityType.Drone;
break;
case 35:
//small crasher
if (EntityColor.Crasher === color) type = EntityType.Crasher;
break;
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
//overseer/overlord drone
if (TeamColors.includes(color)) type = EntityType.Drone;
break;
case 55:
//big crasher
if (EntityColor.Crasher === color) type = EntityType.Crasher;
//triangle
if (EntityColor.Triangle === color) type = EntityType.Triangle;
break;
}
if (type === undefined) type = EntityType.UNKNOWN;
this.#add(type, position, { color, radius });
});
}
#squareHook() {
this.#createPolygonHook(4, (vertices, ctx) => {
vertices = vertices.map((x) => arenaScaling.toArenaPos(x));
const position = Vector.centroid(...vertices);
const radius = Math.round(Vector.radius(...vertices));
const color = ctx.fillStyle;
let type;
switch (radius) {
case 55:
//square
if (EntityColor.Square === color) type = EntityType.Square;
//necromancer drone
if (TeamColors.includes(color) || EntityColor.NecromancerDrone === color)
type = EntityType.Drone;
break;
}
if (type === undefined) type = EntityType.UNKNOWN;
this.#add(type, position, { color, radius });
});
}
#pentagonHook() {
this.#createPolygonHook(5, (vertices, ctx) => {
vertices = vertices.map((x) => arenaScaling.toArenaPos(x));
const position = Vector.centroid(...vertices);
const radius = Math.round(Vector.radius(...vertices));
const color = ctx.fillStyle;
let type;
switch (radius) {
case 75:
if (EntityColor.Pentagon === color) type = EntityType.Pentagon;
break;
case 200:
if (EntityColor.AlphaPentagon === color) type = EntityType.AlphaPentagon;
break;
}
if (type === undefined) type = EntityType.UNKNOWN;
this.#add(type, position, { color, radius });
});
}
#playerHook() {
let index = 0;
let position;
let color;
let radius;
const onCircle = () => {
position = arenaScaling.toArenaPos(position);
radius = arenaScaling.toArenaUnits(new Vector(radius, radius)).x;
let type = EntityType.UNKNOWN;
if (radius > 53) {
type = EntityType.Player;
} else {
type = EntityType.Bullet;
}
this.#add(type, position, {
color,
radius,
});
};
//Sequence: beginPath -> arc -> fill -> beginPath -> arc -> fill -> arc
CanvasKit.hook('beginPath', (target, thisArg, args) => {
//start
if (index !== 3) {
index = 1;
return;
}
if (index === 3) {
index++;
return;
}
index = 0;
});
//check when a circle is drawn.
CanvasKit.hook('arc', (target, thisArg, args) => {
//outline
if (index === 1) {
index++;
const transform = thisArg.getTransform();
position = new Vector(transform.e, transform.f);
radius = transform.a;
return;
}
if (index === 4) {
index++;
color = thisArg.fillStyle;
return;
}
//last arc call
if (index === 6) {
index++;
onCircle();
return;
}
index = 0;
});
CanvasKit.hook('fill', (target, thisArg, args) => {
if (index === 2) {
index++;
return;
}
if (index === 5) {
index++;
return;
}
index = 0;
});
}
}
const entityManager = new EntityManager(); // CONCATENATED MODULE: ./src/index.ts
diepAPI = __webpack_exports__;
/******/
})();
window.diepAPI = diepAPI;
})();