您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
https://github.com/Cazka/diepAPI
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/433681/1129359/diepAPI.js
// ==UserScript== // @name diepAPI // @description https://github.com/Cazka/diepAPI // @version 3.2.0 // @author Cazka // @match https://diep.io/* // @icon https://www.google.com/s2/favicons?domain=diep.io // @namespace https://greasyfork.org/users/541070 // @run-at document-start // @grant none // ==/UserScript== (() => { const _window = 'undefined' == typeof unsafeWindow ? window : unsafeWindow; if (_window.diepAPI) return; //diepAPI start 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__, { apis: () => /* reexport */ apis_namespaceObject, core: () => /* reexport */ core_namespaceObject, extensions: () => /* reexport */ extensions_namespaceObject, tools: () => /* reexport */ tools_namespaceObject, types: () => /* reexport */ types_namespaceObject, }); // NAMESPACE OBJECT: ./src/apis/index.ts var apis_namespaceObject = {}; __webpack_require__.r(apis_namespaceObject); __webpack_require__.d(apis_namespaceObject, { arena: () => arena, camera: () => camera, game: () => game, input: () => input, minimap: () => minimap, player: () => player, playerMovement: () => playerMovement, scaling: () => scaling, }); // NAMESPACE OBJECT: ./src/core/index.ts var core_namespaceObject = {}; __webpack_require__.r(core_namespaceObject); __webpack_require__.d(core_namespaceObject, { CanvasKit: () => CanvasKit, EventEmitter: () => EventEmitter, Movement: () => Movement, Vector: () => Vector, }); // NAMESPACE OBJECT: ./src/extensions/index.ts var extensions_namespaceObject = {}; __webpack_require__.r(extensions_namespaceObject); __webpack_require__.d(extensions_namespaceObject, { debugTool: () => debugTool, entityManager: () => entityManager, }); // NAMESPACE OBJECT: ./src/tools/index.ts var tools_namespaceObject = {}; __webpack_require__.r(tools_namespaceObject); __webpack_require__.d(tools_namespaceObject, { backgroundOverlay: () => backgroundOverlay, overlay: () => overlay, }); // NAMESPACE OBJECT: ./src/types/index.ts var types_namespaceObject = {}; __webpack_require__.r(types_namespaceObject); __webpack_require__.d(types_namespaceObject, { Entity: () => Entity, EntityColor: () => EntityColor, EntityType: () => EntityType, }); // CONCATENATED MODULE: ./src/core/vector.ts class Vector { x; y; constructor(x, y) { this.x = x; this.y = y; } static len(v) { return Math.sqrt(v.x ** 2 + v.y ** 2); } static round(v) { return new Vector(Math.round(v.x), Math.round(v.y)); } static scale(r, v) { return new Vector(r * v.x, r * v.y); } static unscale(r, v) { return new Vector(v.x / r, v.y / r); } static add(u, v) { return new Vector(u.x + v.x, u.y + v.y); } static subtract(u, v) { return new Vector(u.x - v.x, u.y - v.y); } static multiply(u, v) { return new Vector(u.x * v.x, u.y * v.y); } static divide(u, v) { return new Vector(u.x / v.x, u.y / v.y); } 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/core/canvas_kit.ts class CanvasKit { /** * If you need 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; } /** * 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); }, }); } /** * The consumer will be called before */ static hookCtx(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 overrideCtx(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); }, }); } /** * * Calls the callback method when a polygon with `numVertices` is being drawn. */ static hookPolygon(numVertices, cb) { let index = 0; let vertices = []; const onFillPolygon = (ctx) => { cb(vertices, ctx); }; CanvasKit.hookCtx('beginPath', (target, thisArg, args) => { index = 1; vertices = []; }); CanvasKit.hookCtx('moveTo', (target, thisArg, args) => { if (index === 1) { index++; vertices.push(new Vector(args[0], args[1])); return; } index = 0; }); CanvasKit.hookCtx('lineTo', (target, thisArg, args) => { if (index >= 2 && index <= numVertices) { index++; vertices.push(new Vector(args[0], args[1])); return; } index = 0; }); CanvasKit.hookCtx('fill', (target, thisArg, args) => { if (index === numVertices + 1) { index++; onFillPolygon(thisArg); return; } index = 0; }); } } // CONCATENATED MODULE: ./src/core/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/apis/game.ts /** * Events: * - frame: Emitted every frame. Can be used for things that should be executed on every frame * - frame_end: Emitted after `frame` and is mainly used internally to update position variables * - state => (state): Emitted whenever the game changes its state: 'home', 'game', 'stats', 'loading', 'captcha * - s_home: Emitted when the game changes its state to home * - s_game: Emitted when the game changes its state to game * - s_stats: Emitted when the game changes its state to stats * - s_loading: Emitted when the game changes its state to loading * - s_captcha: Emitted when the game changes its state to captcha */ class Game extends EventEmitter { #ready = false; #shadowRoot; constructor() { super(); CanvasKit.hookRAF(() => this.#onframe()); } #onframe() { if (!this.#ready && _window.input !== undefined) { this.#ready = true; this.#onready(); } super.emit('frame'); super.emit('frame_end'); } #onready() { setTimeout(() => super.emit('ready'), 100); this.#shadowRoot = document.querySelector('d-base').shadowRoot; new MutationObserver((mutationList, observer) => { mutationList.forEach((mutation) => { if (mutation.addedNodes.length === 0) { return; } super.emit('state', this.state); super.emit(`s_${this.state}`); return; }); }).observe(this.#shadowRoot, { childList: true }); } get state() { return this.#shadowRoot.querySelector('.screen').tagName.slice(2).toLowerCase(); } get inHome() { return this.state == 'home'; } get inGame() { return this.state == 'game'; } get inStats() { return this.state == 'stats'; } get inLoading() { return this.state == 'loading'; } get isCaptcha() { return this.state == 'captcha'; } } const game = new Game(); // CONCATENATED MODULE: ./src/apis/minimap.ts /** * The Minimap API */ class Minimap { #minimapDim = new Vector(1, 1); #minimapPos = new Vector(0, 0); #viewportDim = new Vector(1, 1); #viewportPos = new Vector(1, 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]; return; } return 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; } #minimapHook() { CanvasKit.hookCtx('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.overrideCtx('fillRect', (target, thisArg, args) => { const transform = thisArg.getTransform(); if (thisArg.globalAlpha !== 0.1) { return Reflect.apply(target, thisArg, args); } if ( Math.abs(transform.a / transform.d - _window.innerWidth / _window.innerHeight) > (_window.innerWidth / _window.innerHeight) * 0.000_05 ) { 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() { CanvasKit.hookPolygon(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])); if (side1 === side2 && side2 === side3) return; const centroid = Vector.centroid(...vertices); const arrowPos = Vector.subtract(centroid, this.#minimapPos); const position = Vector.divide(arrowPos, this.#minimapDim); this.#arrowPos = position; }); } } const minimap = new Minimap(); // CONCATENATED MODULE: ./src/apis/camera.ts class Camera { #position; constructor() { game.on('frame_end', () => { const center = Vector.add(minimap.viewportPos, Vector.unscale(2, minimap.viewportDim)); const cameraPos = Vector.subtract(center, minimap.minimapPos); const normalized = Vector.divide(cameraPos, minimap.minimapDim); this.#position = arena.scale(normalized); }); } get position() { return this.#position; } } const camera = new Camera(); // CONCATENATED MODULE: ./src/apis/scaling.ts class Scaling { #scalingFactor = 1; #drawSolidBackground = false; constructor() { // TODO: game.on('ready') setTimeout(() => { _window.input.set_convar = new Proxy(_window.input.set_convar, { apply: (target, thisArg, args) => { if (args[0] === 'ren_solid_background') this.#drawSolidBackground = args[1]; else Reflect.apply(target, thisArg, args); }, }); }, 1000); CanvasKit.overrideCtx('stroke', (target, thisArg, args) => { if (thisArg.fillStyle !== '#cdcdcd') { return Reflect.apply(target, thisArg, args); } if (thisArg.globalAlpha === 0) { return Reflect.apply(target, thisArg, args); } this.#scalingFactor = thisArg.globalAlpha * 10; if (!this.#drawSolidBackground) { return Reflect.apply(target, thisArg, args); } }); } get windowRatio() { return Math.max(_window.innerWidth / 1920, _window.innerHeight / 1080); } get scalingFactor() { return this.#scalingFactor; } 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.round(Vector.unscale(this.#scalingFactor, v)); } /** * * @param {Vector} v The vector in arena units * @returns {Vector} The vector in canvas units */ toCanvasUnits(v) { return Vector.round(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 scaling = new Scaling(); // CONCATENATED MODULE: ./src/apis/arena.ts class Arena { #size = 1; constructor() { setInterval(() => { const ratio = Vector.divide(minimap.minimapDim, minimap.viewportDim); const arenaDim = Vector.multiply(ratio, scaling.screenToCanvas(new Vector(_window.innerWidth, _window.innerHeight))); const arenaSize = scaling.toArenaUnits(arenaDim); this.#size = arenaSize.x; }, 16); } /** * @returns {number} The Arena size in arena units */ get size() { return this.#size; } /** * * @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/apis/input.ts const sleep = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms)); class Input { #gameCanvas; constructor() { game.once('ready', () => { this.#gameCanvas = document.getElementById('canvas'); }); } keyDown(key) { if (typeof key == 'string') { key = this.#toKeyCode(key); } const keydown = new KeyboardEvent('keydown', { key: '', code: '', keyCode: key, which: key, cancelable: true, composed: true, bubbles: true, }); _window.dispatchEvent(keydown); } keyUp(key) { if (typeof key == 'string') { key = this.#toKeyCode(key); } const keyup = new KeyboardEvent('keyup', { key: '', code: '', keyCode: key, which: key, cancelable: true, composed: true, bubbles: true, }); _window.dispatchEvent(keyup); } async keyPress(key) { this.keyDown(key); await sleep(200); this.keyUp(key); await sleep(10); } mouse(x, y) { const mousemove = new MouseEvent('mousemove', { clientX: x, clientY: y, cancelable: true, composed: true, bubbles: true, }); this.#gameCanvas.dispatchEvent(mousemove); } #toKeyCode(key) { if (key.length != 1) { throw new Error(`diepAPI: Unsupported key: ${key}`); } return key.toUpperCase().charCodeAt(0); } } const input = new Input(); // CONCATENATED MODULE: ./src/apis/gamepad.ts class Gamepad { #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 = 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 Gamepad(); // CONCATENATED MODULE: ./src/core/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.unscale(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.unscale( this.#velocitySamples.length, this.#velocitySamples.reduce((acc, x) => Vector.add(acc, x)) ); } } // CONCATENATED MODULE: ./src/apis/player_movement.ts class PlayerMovement extends Movement { /** * Using the minimap arrow to get the player position and velocity */ constructor() { super(); game.on('frame_end', () => super.updatePos(arena.scale(minimap.arrowPos))); } } const playerMovement = new PlayerMovement(); // CONCATENATED MODULE: ./src/apis/player.ts const player_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); #username = _window.localStorage.name; #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 = scaling.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); }, }); // username _window.input.trySpawn = new Proxy(_window.input.trySpawn, { apply: (target, thisArg, args) => { this.#username = args[0]; return Reflect.apply(target, thisArg, args); }, }); // tank and level event listener CanvasKit.hookCtx('fillText', (target, thisArg, args) => { const text = args[0]; const match = text.match(/^Lvl (\d+) (\w+\s?\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); } async #ondead() { await player_sleep(50); super.emit('dead'); } async #onspawn() { this.#gamemode = _window.localStorage.gamemode; await player_sleep(50); super.emit('spawn'); } useGamepad(value) { gamepad.connected = value; } async spawn(name = this.#username) { if (!this.#isDead) { return; } _window.input.trySpawn(name); } async upgrade_stat(id, level) { if (id < 1 || id > 8) throw `diepAPI: ${id} is not a supported stat`; input.keyDown(85); for (let i = 0; i < level; i++) { await input.keyPress(48 + id); } input.keyUp(85); await player_sleep(250); } async upgrade_tank(index) { index -= 1; const x_index = index % 2; const y_index = Math.floor(index / 2); const x = scaling.screenToCanvasUnits(scaling.windowRatio * (x_index * 115 + 97.5)); const y = scaling.screenToCanvasUnits(scaling.windowRatio * (y_index * 110 + 120)); this.#mouseLock = true; input.mouse(x, y); await input.keyPress(1); // wait 200 ms before disabling mouselock await player_sleep(200); this.#mouseLock = false; // wait 1500 ms for the animation to finish await player_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) { input.keyUp('a'); input.keyDown('d'); } else if (direction.x < 0) { input.keyUp('d'); input.keyDown('a'); } else { input.keyUp('a'); input.keyUp('d'); } if (direction.y > 0) { input.keyUp('w'); input.keyDown('s'); } else if (direction.y < 0) { input.keyUp('s'); input.keyDown('w'); } else { input.keyUp('w'); input.keyUp('s'); } } } lookAt(arenaPos) { const position = scaling.toCanvasPos(arenaPos); input.mouse(position.x, position.y); this.#onmousemove({ clientX: position.x, clientY: position.y }); } #onmousemove(e) { this.#mouseCanvasPos = scaling.screenToCanvas(new Vector(e.clientX, e.clientY)); if (gamepad.connected) { const arenaPos = scaling.toArenaPos(this.#mouseCanvasPos); const direction = Vector.subtract(arenaPos, this.position); let axes = Vector.scale(scaling.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/apis/index.ts // CONCATENATED MODULE: ./src/core/index.ts // CONCATENATED MODULE: ./src/types/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; parent; extras; constructor(type, parent, extras) { super(); this.type = type; this.parent = parent; this.extras = extras; } updatePos(newPos) { super.updatePos(newPos); } } // CONCATENATED MODULE: ./src/extensions/extension.ts class Extension { onload; #loaded = false; constructor(onload) { this.onload = onload; } load() { if (this.#loaded) { return; } this.#loaded = true; this.onload(); } } // CONCATENATED MODULE: ./src/extensions/entity_manager.ts const random_id = () => Math.random().toString(36).slice(2, 5); /** * 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 extends Extension { #entities = []; #entitiesLastFrame = this.#entities; constructor() { super(() => { game.on('frame_end', () => { this.#entitiesLastFrame = this.#entities; this.#entities = []; }); this.#triangleHook(); this.#squareHook(); this.#pentagonHook(); //when is a bullet being drawn? //when is a player being drawn? this.#playerHook(); }); } get entities() { return this.#entities; } /** * * @returns The own player entity */ getPlayer() { const player = this.#entities.filter( (entity) => entity.type == EntityType.Player && Vector.distance(entity.position, playerMovement.position) < 28 ); return player[0]; } /** * Adds the entity to `#entities`. * * Will either find the entity in `#entitiesLastFrame` or create a new `Entity`. */ #add(type, position, extras = {}) { let entity = this.#findEntity(type, position); if (!entity) { const parent = this.#findParent(type, position); entity = new Entity(type, parent, { id: random_id(), timestamp: performance.now(), ...extras, }); } //TODO: remove radius from extras entity.extras.radius = extras.radius; entity.updatePos(position); this.#entities.push(entity); } /** * If an entity is newly created, try to find it's parent entity. */ #findParent(type, position) { if (type == EntityType.Bullet) { // TODO: do we want to change the parent entity to EntityType.Barrel in the future? return this.#findEntity(EntityType.Player, position, 300); } } /** * Searches `#entitiesLastFrame` for the entity that is closest to `position` * @returns the entity or null if there is no match. */ #findEntity(type, position, tolerance = 42) { let result = null; let shortestDistance = Infinity; this.#entitiesLastFrame.forEach((entity, i) => { if (entity.type !== type) return; const distance = Vector.distance(entity.position, position); if (distance < shortestDistance) { shortestDistance = distance; result = entity; } }); if (shortestDistance > tolerance) { return null; } return result; } #triangleHook() { CanvasKit.hookPolygon(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) => scaling.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() { CanvasKit.hookPolygon(4, (vertices, ctx) => { vertices = vertices.map((x) => scaling.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() { CanvasKit.hookPolygon(5, (vertices, ctx) => { vertices = vertices.map((x) => scaling.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 = scaling.toArenaPos(position); radius = scaling.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.hookCtx('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.hookCtx('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.hookCtx('fill', (target, thisArg, args) => { if (index === 2) { index++; return; } if (index === 5) { index++; return; } index = 0; }); } } const entityManager = new EntityManager(); // CONCATENATED MODULE: ./src/tools/overlay.ts class Overlay { canvas; ctx; constructor() { this.canvas = CanvasKit.createCanvas(); this.ctx = this.canvas.getContext('2d'); document.body.appendChild(this.canvas); _window.addEventListener('resize', () => this.#onResize()); game.on('frame', () => this.#onFrame()); this.#onResize(); } #onResize() { this.canvas.width = _window.innerWidth * _window.devicePixelRatio; this.canvas.height = _window.innerHeight * _window.devicePixelRatio; } #onFrame() { this.canvas.width = _window.innerWidth * _window.devicePixelRatio; this.canvas.height = _window.innerHeight * _window.devicePixelRatio; this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.setTransform(1, 0, 0, 1, 0, 0); } } const overlay = new Overlay(); // CONCATENATED MODULE: ./src/extensions/debug_tool.ts class DebugTool extends Extension { #drawBoundingBox = false; #drawVelocity = false; #drawParent = false; #drawInfo = false; #drawStats = false; constructor() { super(() => { entityManager.load(); game.on('frame', () => { entityManager.entities.forEach((entity) => { const position = scaling.toCanvasPos(entity.position); const futurePos = scaling.toCanvasPos(entity.predictPos(1000)); const dimensions = scaling.toCanvasUnits(new Vector(2 * entity.extras.radius, 2 * entity.extras.radius)); if (this.#drawBoundingBox) { this.#_drawboundingBox(entity, position, dimensions); } if (this.#drawVelocity) { this.#_drawVelocity(position, futurePos); } if (this.#drawParent) { this.#_drawParent(entity, position); } if (this.#drawInfo) { this.#_drawInfo(entity, position, dimensions); } }); if (this.#drawStats) { this.#_drawStats(); } }); }); } drawAll(v) { this.#drawBoundingBox = v; this.#drawVelocity = v; this.#drawParent = v; this.#drawInfo = v; this.#drawStats = v; } drawBoundingBox(v) { this.#drawBoundingBox = v; } drawVelocity(v) { this.#drawVelocity = v; } drawParent(v) { this.#drawParent = v; } drawInfo(v) { this.#drawInfo = v; } drawStats(v) { this.#drawStats = v; } #_drawboundingBox(entity, position, dimensions) { overlay.ctx.save(); overlay.ctx.strokeStyle = entity.type === EntityType.UNKNOWN ? '#ffffff' : entity.extras.color; overlay.ctx.lineWidth = scaling.toCanvasUnits(new Vector(5, 5)).x; overlay.ctx.strokeRect(position.x - dimensions.x / 2, position.y - dimensions.y / 2, dimensions.x, dimensions.y); overlay.ctx.restore(); } #_drawVelocity(position, futurePos) { overlay.ctx.save(); overlay.ctx.strokeStyle = '#000000'; overlay.ctx.lineWidth = scaling.toCanvasUnits(new Vector(5, 5)).x; overlay.ctx.beginPath(); overlay.ctx.moveTo(position.x, position.y); overlay.ctx.lineTo(futurePos.x, futurePos.y); overlay.ctx.stroke(); overlay.ctx.restore(); } #_drawParent(entity, position) { if (entity.parent == null) { return; } const parentPos = scaling.toCanvasPos(entity.parent.position); overlay.ctx.save(); overlay.ctx.strokeStyle = '#8aff69'; overlay.ctx.lineWidth = scaling.toCanvasUnits(new Vector(5, 5)).x; overlay.ctx.beginPath(); overlay.ctx.moveTo(position.x, position.y); overlay.ctx.lineTo(parentPos.x, parentPos.y); overlay.ctx.stroke(); overlay.ctx.restore(); } #_drawInfo(entity, position, dimensions) { overlay.ctx.save(); const fontSize = scaling.toCanvasUnits(new Vector(30, 30)).x; overlay.ctx.font = fontSize + 'px Ubuntu'; overlay.ctx.fillStyle = `#ffffff`; overlay.ctx.strokeStyle = '#000000'; overlay.ctx.lineWidth = fontSize / 5; overlay.ctx.strokeText( `${entity.extras.id} ${Math.floor((performance.now() - entity.extras.timestamp) / 1000)}`, position.x, position.y - dimensions.y * 0.7 ); overlay.ctx.fillText( `${entity.extras.id} ${Math.floor((performance.now() - entity.extras.timestamp) / 1000)}`, position.x, position.y - dimensions.y * 0.7 ); overlay.ctx.restore(); } #_drawStats() { const text = `Debug Tool: Game Info: gamemode: ${player.gamemode} entities: ${entityManager.entities.length} Player Info: Is dead: ${player.isDead} level: ${player.level} tank: ${player.tank} position: ${Math.round(player.position.x)},${Math.round(player.position.y)} mouse: ${Math.round(player.mouse.x)},${Math.round(player.mouse.y)} velocity [units/seconds]: ${Math.round(Math.hypot(player.velocity.x, player.velocity.y))}`; overlay.ctx.save(); const fontSize = 20 * _window.devicePixelRatio; overlay.ctx.font = `${fontSize}px Ubuntu`; overlay.ctx.fillStyle = `#ffffff`; overlay.ctx.strokeStyle = '#000000'; overlay.ctx.lineWidth = fontSize / 5; text.split('\n').forEach((x, i) => { overlay.ctx.strokeText(x, 0, _window.innerHeight * 0.25 + i * fontSize * 1.05); overlay.ctx.fillText(x, 0, _window.innerHeight * 0.25 + i * fontSize * 1.05); }); overlay.ctx.restore(); } } const debugTool = new DebugTool(); // CONCATENATED MODULE: ./src/extensions/index.ts // CONCATENATED MODULE: ./src/tools/background_overlay.ts class BackgroundOverlay { canvas; ctx; #gameCanvas; #gameContext; constructor() { this.canvas = CanvasKit.createCanvas(); this.ctx = this.canvas.getContext('2d'); _window.addEventListener('resize', () => this.#onResize()); game.on('frame', () => this.#onFrame()); this.#onResize(); game.once('ready', () => { this.#gameCanvas = document.getElementById('canvas'); this.#gameContext = this.#gameCanvas.getContext('2d'); this.#hookBackground(); }); } #onResize() { this.canvas.width = _window.innerWidth * _window.devicePixelRatio; this.canvas.height = _window.innerHeight * _window.devicePixelRatio; } #onFrame() { this.canvas.width = _window.innerWidth * _window.devicePixelRatio; this.canvas.height = _window.innerHeight * _window.devicePixelRatio; this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.setTransform(1, 0, 0, 1, 0, 0); } #hookBackground() { CanvasKit.overrideCtx('fillRect', (target, thisArg, args) => { if (typeof thisArg.fillStyle !== 'object') { return Reflect.apply(target, thisArg, args); } const result = Reflect.apply(target, thisArg, args); this.#gameContext.save(); this.#gameContext.setTransform(1, 0, 0, 1, 0, 0); this.#gameContext.globalAlpha = 1; this.#gameContext.drawImage(this.canvas, 0, 0); this.#gameContext.restore(); return result; }); } } const backgroundOverlay = new BackgroundOverlay(); // CONCATENATED MODULE: ./src/tools/index.ts // CONCATENATED MODULE: ./src/types/index.ts // CONCATENATED MODULE: ./src/index.ts diepAPI = __webpack_exports__; /******/ })(); //diepAPI end _window.diepAPI = diepAPI; })();