UNPKG

@nxg-org/mineflayer-custom-pvp

Version:

Intermediate functionality for bow and sword pvp.

728 lines (727 loc) 37 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SwordPvp = void 0; const mineflayer_util_plugin_1 = require("@nxg-org/mineflayer-util-plugin"); const stream_1 = require("stream"); const vec3_1 = require("vec3"); const mathUtils_1 = require("../calc/mathUtils"); const util_1 = require("../util"); const swordconfigs_1 = require("./swordconfigs"); const sworddata_1 = require("./sworddata"); const swordutil_1 = require("./swordutil"); const { getEntityAABB } = mineflayer_util_plugin_1.AABBUtils; const PIOver3 = Math.PI / 3; /** * The main pvp manager plugin class. */ class SwordPvp extends stream_1.EventEmitter { constructor(bot, options = (0, swordconfigs_1.getConfig)(bot)) { var _a; super(); this.bot = bot; this.options = options; this.ticksToNextAttack = 0; this.ticksSinceTargetAttack = 0; this.ticksSinceLastHurt = 0; this.ticksSinceLastTargetHit = 0; this.ticksSinceLastSwitch = 0; this.wasInRange = false; this.wasVisible = false; this.weaponOfChoice = "sword"; this.willBeFirstHit = true; this.tickOverride = false; this.targetShielding = false; this.strafeCounter = 0; this.checkForShield = () => __awaiter(this, void 0, void 0, function* () { var _b; if (!this.target) return; if (!this.options.shieldDisableConfig.enabled) return; if (this.bot.supportFeature("doesntHaveOffHandSlot")) return; // no need for 1.8 pvp. if (this.target.metadata[8] === 3 && ((_b = this.target.equipment[1]) === null || _b === void 0 ? void 0 : _b.name) === "shield") { if (!this.targetShielding) this.ticksSinceLastSwitch = 0; this.targetShielding = true; if (this.ticksSinceTargetAttack >= 3 && this.ticksSinceLastSwitch >= 3 && !this.tickOverride) { const itemToChangeTo = yield this.checkForWeapon("_axe"); if (itemToChangeTo) { const switched = yield this.equipWeapon(itemToChangeTo); if (switched) { this.weaponOfChoice = "_axe"; this.tickOverride = true; switch (this.options.shieldDisableConfig.mode) { case "single": case "double": this.tickOverride = true; yield this.bot.waitForTicks(3); yield this.attemptAttack("disableshield"); if (this.options.shieldDisableConfig.mode === "single") break; yield this.bot.waitForTicks(3); yield this.attemptAttack("doubledisableshield"); } this.tickOverride = false; } } } } else { if (this.targetShielding) this.ticksSinceLastSwitch = 0; this.targetShielding = false; if (this.weaponOfChoice === "sword" || this.tickOverride) return; //assume already attacking const itemToChangeTo = yield this.checkForWeapon("sword"); if (itemToChangeTo) { const switched = yield this.equipWeapon(itemToChangeTo); if (switched) { this.weaponOfChoice = "sword"; this.ticksToNextAttack = this.meleeAttackRate.getTicks(this.bot.heldItem); } } } }); this.swingUpdate = (entity) => __awaiter(this, void 0, void 0, function* () { if (entity === this.target) { this.ticksSinceTargetAttack = 0; } }); this.lastHealth = 20; this.removalUpdate = (entity) => __awaiter(this, void 0, void 0, function* () { if (this.target == null) return; if (entity.id === this.target.id) { this.stop(); } }); this.hurtUpdate = (entity) => __awaiter(this, void 0, void 0, function* () { var _c; if (!this.target) return; if (entity === this.bot.entity) { if ((_c = this.lastHealth <= this.bot.health) !== null && _c !== void 0 ? _c : 20) { this.lastHealth = this.bot.health; return; } this.lastHealth = this.bot.health; this.ticksSinceLastHurt = 0; if (this.ticksSinceTargetAttack < 6) this.ticksSinceLastTargetHit = 0; // console.log('hey', entity === this.target, entity.name, this.target?.name, this.ticksSinceLastHurt, this.ticksSinceLastTargetHit, this.ticksSinceTargetAttack) if (this.options.onHitConfig.kbCancel.enabled) { switch (this.options.onHitConfig.kbCancel.mode) { case "velocity": yield new Promise((resolve, reject) => { const listener = (packet) => { const entity = this.bot.entities[packet.entityId]; if (entity === this.bot.entity) { if (this.options.onHitConfig.kbCancel.mode !== "velocity") return; if (this.options.onHitConfig.kbCancel.hRatio || this.options.onHitConfig.kbCancel.hRatio === 0) { this.bot.entity.velocity.x *= this.options.onHitConfig.kbCancel.hRatio; this.bot.entity.velocity.z *= this.options.onHitConfig.kbCancel.hRatio; } if (this.options.onHitConfig.kbCancel.yRatio || this.options.onHitConfig.kbCancel.yRatio === 0) this.bot.entity.velocity.y *= this.options.onHitConfig.kbCancel.yRatio; this.bot._client.removeListener("entity_velocity", listener); resolve(); } }; setTimeout(() => { this.bot._client.removeListener("entity_velocity", listener); resolve(); }, 500); this.bot._client.on("entity_velocity", listener); }); return; case "jump": case "jumpshift": if ((0, mathUtils_1.lookingAt)(entity, this.target, this.options.genericConfig.enemyReach)) { this.bot.setControlState("right", false); this.bot.setControlState("left", false); this.bot.setControlState("back", false); this.bot.setControlState("sneak", false); this.bot.setControlState("forward", true); this.bot.setControlState("sprint", true); this.bot.setControlState("jump", true); this.bot.setControlState("jump", false); } if (this.options.onHitConfig.kbCancel.mode === "jump") break; case "shift": if ((0, mathUtils_1.lookingAt)(entity, this.target, this.options.genericConfig.enemyReach)) { this.bot.setControlState("sneak", true); yield this.bot.waitForTicks(this.options.onHitConfig.kbCancel.delay || 5); this.bot.setControlState("sneak", false); this.bot.setControlState("sprint", true); } break; } } yield new Promise((res, rej) => { const listener = (packet) => { const entity = this.bot.entities[packet.entityId]; if (entity !== this.bot.entity) return; this.bot._client.removeListener("entity_velocity", listener); clearTimeout(timeout); res(undefined); }; const timeout = setTimeout(() => { this.bot._client.removeListener("entity_velocity", listener); res(undefined); }, 500); this.bot._client.on("entity_velocity", listener); }); if (this.options.swingConfig.mode === "fullswing") this.reactionaryCrit(); } }); // per tick. this.update = () => { if (!this.target) return; this.ticksToNextAttack--; this.ticksSinceTargetAttack++; this.ticksSinceLastHurt++; this.ticksSinceLastTargetHit++; this.ticksSinceLastSwitch++; this.checkRange(); this.checkVisibility(); this.rotate(); this.doMove(); this.doStrafe(); this.causeCritical(); this.toggleShield(); if (this.ticksToNextAttack <= -1 && !this.tickOverride) { if (this.bot.entity.velocity.y <= -0.25) this.bot.setControlState("sprint", false); if (this.bot.entity.onGround) this.sprintTap(); this.attemptAttack("normal"); } }; this.meleeAttackRate = bot.supportFeature("doesntHaveOffHandSlot") ? new sworddata_1.OldPVPTicks(bot, (_a = options.cps) !== null && _a !== void 0 ? _a : 15) : new sworddata_1.NewPVPTicks(bot); const oldEmit = this.bot.emit.bind(this.bot); const oldEmit1 = this.bot._client.emit.bind(this.bot._client); // this.bot.emit = ((event: any, ...args: any[]) => { // if (event.startsWith("entity")) console.log(event, args) // return oldEmit(event, ...args) // }) // this.bot._client.emit = ((event: any, ...args: any[]) => { // if (!event.includes("chunk")) console.log(event, args) // return oldEmit1(event, ...args) // }) this.bot.on("physicsTick", this.update); this.bot.on("physicsTick", this.checkForShield); this.bot.on("entitySwingArm", this.swingUpdate); this.bot.on("entityUpdate", this.hurtUpdate); this.bot.on("entityDead", this.removalUpdate); this.bot.on("entityGone", this.removalUpdate); // 1.8.8 compat. // this.bot.on("entityHurt", this.hurtUpdate); // this.bot.on('health', this.hurtUpdate.bind(this, this.bot.entity)) } changeWeaponState(weapon) { const hasWeapon = this.checkForWeapon(weapon); if (hasWeapon) { this.weaponOfChoice = weapon; return hasWeapon; } return null; } checkForWeapon(weapon) { if (!weapon) weapon = this.weaponOfChoice; const heldItem = this.bot.inventory.slots[this.bot.getEquipmentDestSlot("hand")]; if (heldItem === null || heldItem === void 0 ? void 0 : heldItem.name.includes(weapon)) { return heldItem; } else { const item = this.bot.util.inv.getAllItems().find((item) => item === null || item === void 0 ? void 0 : item.name.includes(weapon)); return item ? item : null; } } equipWeapon(weapon) { return __awaiter(this, void 0, void 0, function* () { const heldItem = this.bot.inventory.slots[this.bot.getEquipmentDestSlot("hand")]; return (heldItem === null || heldItem === void 0 ? void 0 : heldItem.name) === weapon.name ? true : yield this.bot.util.inv.customEquip(weapon, "hand"); }); } entityWeapon(entity) { var _a; return (_a = (entity !== null && entity !== void 0 ? entity : this.bot.entity)) === null || _a === void 0 ? void 0 : _a.heldItem; } entityShieldStatus(entity) { entity = entity !== null && entity !== void 0 ? entity : this.bot.entity; const shieldSlot = entity.equipment[1]; return (shieldSlot === null || shieldSlot === void 0 ? void 0 : shieldSlot.name) === "shield" && this.bot.util.entity.isOffHandActive(entity); } clearShieldToggleListener() { if (!this.shieldToggleListener) return; this.off("attackedTarget", this.shieldToggleListener); this.shieldToggleListener = undefined; } attack(target) { var _a; return __awaiter(this, void 0, void 0, function* () { if ((target === null || target === void 0 ? void 0 : target.id) === ((_a = this.target) === null || _a === void 0 ? void 0 : _a.id)) return; this.stop(); this.target = target; if (!this.target) return; this.ticksToNextAttack = 0; const itemToChangeTo = yield this.checkForWeapon(); if (itemToChangeTo) yield this.equipWeapon(itemToChangeTo); this.bot.tracker.trackEntity(target); this.bot.tracker.trackEntity(this.bot.entity); this.emit("startedAttacking", this.target); }); } stop() { if (!this.target) return; this.clearShieldToggleListener(); this.lastTarget = this.target; this.bot.tracker.stopTrackingEntity(this.target); this.target = undefined; this.targetGoal = undefined; (0, swordutil_1.stopFollow)(this.bot, this.options.followConfig.mode); this.bot.clearControlStates(); this.emit("stoppedAttacking"); } getEntityEyeHeight(entity) { // Vanilla interaction reach is measured from the eye position. // Prismarine entities do not expose eye height directly, so we approximate it from the current hitbox height. return entity.height * 0.9; } getEntityEyePosition(entity) { return entity.position.offset(0, this.getEntityEyeHeight(entity), 0); } botReach() { if (!this.target) return 10000; return getEntityAABB(this.target).distanceToVec(this.getEntityEyePosition(this.bot.entity)); } targetReach() { if (!this.target) return 10000; return getEntityAABB(this.bot.entity).distanceToVec(this.getEntityEyePosition(this.target)); } checkRange() { if (!this.target) return; const dist = this.target.position.distanceTo(this.bot.entity.position); if (dist > this.options.genericConfig.viewDistance) return this.stop(); const inRange = this.botReach() <= this.options.genericConfig.attackRange; if (!this.wasInRange && inRange && this.options.swingConfig.mode === "killaura") this.ticksToNextAttack = -1; this.wasInRange = inRange; } checkVisibility() { if (!this.target) return; // first check, see if bounding boxes are collided. // If so, we can obviously see them. const bb0 = getEntityAABB(this.bot.entity); const bb1 = getEntityAABB(this.target); if (bb0.intersects(bb1)) { this.wasVisible = true; return; } const eyePos = this.getEntityEyePosition(this.bot.entity); const eyeDir = this.bot.util.getViewDir(); const reach = this.options.genericConfig.attackRange; const hit = this.bot.util.raytrace.entityRaytrace(eyePos, eyeDir, reach, (e) => { var _a; return e.id === ((_a = this.target) === null || _a === void 0 ? void 0 : _a.id); }); this.wasVisible = hit === this.target; if (this.wasVisible) return; } causeCritical() { return __awaiter(this, void 0, void 0, function* () { if (!this.options.critConfig.enabled || !this.target) return false; if (this.bot.entity.isInWater || this.bot.entity.isInLava) return false; switch (this.options.critConfig.mode) { case "packet": if (this.ticksToNextAttack !== -1) return false; if (!this.wasInRange) return false; if (!this.wasVisible) return false; if (!this.bot.entity.onGround) return false; if (this.options.critConfig.bypass) { this.bot.setControlState("sprint", false); this.bot._client.write("position", Object.assign(Object.assign({}, this.bot.entity.position.offset(0, 0.11, 0)), { onGround: false })); this.bot._client.write("position", Object.assign(Object.assign({}, this.bot.entity.position.offset(0, 0.1100013579, 0)), { onGround: false })); this.bot._client.write("position", Object.assign(Object.assign({}, this.bot.entity.position.offset(0, 0.0000013579, 0)), { onGround: false })); } else { this.bot._client.write("position", Object.assign(Object.assign({}, this.bot.entity.position.offset(0, 0.1625, 0)), { onGround: false })); this.bot._client.write("position", Object.assign(Object.assign({}, this.bot.entity.position.offset(0, 4.0e-6, 0)), { onGround: false })); this.bot._client.write("position", Object.assign(Object.assign({}, this.bot.entity.position.offset(0, 1.1e-6, 0)), { onGround: false })); this.bot._client.write("position", Object.assign(Object.assign({}, this.bot.entity.position), { onGround: false })); } return true; case "shorthop": if (this.ticksToNextAttack !== 1) return false; if (!this.bot.entity.onGround) return false; if (this.botReach() <= (this.options.critConfig.attemptRange || this.options.genericConfig.attackRange)) return false; this.bot.entity.position = this.bot.entity.position.offset(0, 0.25, 0); this.bot.entity.onGround = false; yield this.bot.waitForTicks(2); const { x: dx, y: dy, z: dz } = this.bot.entity.position; this.bot.entity.position = this.bot.entity.position.set(dx, Math.floor(dy), dz); return true; case "hop": if (this.ticksToNextAttack > 8) return false; const inReach = this.botReach() <= (this.options.critConfig.attemptRange || this.options.genericConfig.attackRange); if (!inReach) return false; if (this.ticksToNextAttack !== 8 && !this.willBeFirstHit) { return false; } if (this.willBeFirstHit && !this.bot.entity.onGround) { this.reactionaryCrit(true); return true; } this.bot.setControlState("jump", true); this.bot.setControlState("jump", false); return true; default: return false; } }); } doMove() { var _a; return __awaiter(this, void 0, void 0, function* () { if (!this.target) { this.bot.clearControlStates(); return; } const farAway = this.botReach() >= this.options.genericConfig.attackRange; if (farAway) { const goal = (0, swordutil_1.generateGoal)(this.bot, this.target, this.options); if (!this.targetGoal || !(0, swordutil_1.goalEquals)(this.bot, this.targetGoal, goal, this.options)) { this.targetGoal = (0, swordutil_1.followEntity)(this.bot, goal, this.options); } } else { if (this.targetGoal) { (0, swordutil_1.stopFollow)(this.bot, this.options.followConfig.mode); this.targetGoal = undefined; } let shouldApproach = true; if (this.options.onHitConfig.enabled) { const distCheck = this.targetReach() <= this.options.genericConfig.enemyReach + 1; switch (this.options.onHitConfig.mode) { case "backoff": shouldApproach = this.ticksSinceLastHurt > ((_a = this.options.onHitConfig.tickCount) !== null && _a !== void 0 ? _a : 5) && distCheck; break; } } const tooClose = this.botReach() > this.options.genericConfig.tooCloseRange; shouldApproach = shouldApproach && tooClose; if (!this.bot.getControlState("back")) { this.bot.setControlState("forward", shouldApproach); this.bot.setControlState("sprint", shouldApproach); } } }); } doStrafe() { var _a; return __awaiter(this, void 0, void 0, function* () { if (!this.target) { if (this.currentStrafeDir) { this.bot.setControlState(this.currentStrafeDir, false); this.currentStrafeDir = undefined; } return false; } if (!this.options.strafeConfig.enabled) return false; const diff = (0, mathUtils_1.getTargetYaw)(this.target.position, this.bot.entity.position) - this.target.yaw; const shouldMove = Math.abs(diff) < ((_a = this.options.strafeConfig.mode.maxOffset) !== null && _a !== void 0 ? _a : PIOver3); // console.log('shouldMove', shouldMove) if (!shouldMove) { if (this.currentStrafeDir) this.bot.setControlState(this.currentStrafeDir, false); this.currentStrafeDir = undefined; return; } switch (this.options.strafeConfig.mode.mode) { case "circle": const circleDir = diff < 0 ? "right" : "left"; if (circleDir !== this.currentStrafeDir) { if (this.currentStrafeDir) this.bot.setControlState(this.currentStrafeDir, false); } this.currentStrafeDir = circleDir; this.bot.setControlState(circleDir, true); break; case "random": if (this.strafeCounter < 0) { this.strafeCounter = Math.floor(Math.random() * 20) + 5; const rand = Math.random(); const randomDir = rand < 0.5 ? "left" : "right"; const oppositeDir = rand >= 0.5 ? "left" : "right"; if (this.botReach() <= this.options.genericConfig.attackRange + 3) { this.bot.setControlState(randomDir, true); this.bot.setControlState(oppositeDir, false); this.currentStrafeDir = randomDir; } } this.strafeCounter--; break; case "intelligent": // console.log(this.ticksSinceLastTargetHit, this.currentStrafeDir, this.strafeCounter) if (this.ticksSinceLastTargetHit > 40) { this.bot.setControlState("left", false); this.bot.setControlState("right", false); this.currentStrafeDir = undefined; } else { if (this.strafeCounter < 0 || this.currentStrafeDir === undefined) { this.strafeCounter = Math.floor(Math.random() * 20) + 5; const intelliRand = Math.random(); const smartDir = intelliRand < 0.5 ? "left" : "right"; const oppositeSmartDir = intelliRand >= 0.5 ? "left" : "right"; this.currentStrafeDir = smartDir; } const oppositeSmartDir = this.currentStrafeDir === "left" ? "right" : "left"; if (this.botReach() <= this.options.genericConfig.attackRange + 3) { this.bot.setControlState(this.currentStrafeDir, true); this.bot.setControlState(oppositeSmartDir, false); // console.log('set',this.currentStrafeDir, 'true', oppositeSmartDir, 'false') // console.log(this.bot.getControlState('left'), this.bot.getControlState('right'), this.botReach(), this.options.genericConfig.attackRange + 3) } else { if (this.currentStrafeDir) this.bot.setControlState(this.currentStrafeDir, false); this.currentStrafeDir = undefined; } } // console.log(this.bot.getControlState('left'), this.bot.getControlState('right'), this.botReach(), this.options.genericConfig.attackRange + 3) this.strafeCounter--; } }); } sprintTap() { var _a; return __awaiter(this, void 0, void 0, function* () { if (!this.target) return; if (!this.bot.entity.onGround) return false; if (!this.wasInRange) return false; if (!this.wasVisible) return false; if (!this.options.tapConfig.enabled) return false; switch (this.options.tapConfig.mode) { case "wtap": this.bot.setControlState("forward", false); this.bot.setControlState("sprint", false); this.bot.setControlState("forward", true); this.bot.setControlState("sprint", true); break; case "stap": // if (this.bot.getControlState("back")) { // this.bot.setControlState("forward", true); // this.bot.setControlState("sprint", true); // this.bot.setControlState("back", false); // } // const listener = () => { // if (!this.target) return cleanup(); // this.bot.setControlState("forward", false); // this.bot.setControlState("sprint", false); // this.bot.setControlState("back", true); // const looking = movingAt( // this.target.position, // this.bot.entity.position, // // this.options.genericConfig.enemyReach // this.bot.tracker.getEntitySpeed(this.target) ?? new Vec3(0, 0, 0), // PIOver3 // ); // if (!looking && this.wasInRange) cleanup(); // if (this.botReach() < this.options.genericConfig.attackRange + 0.1) cleanup(); // } // const cleanup = () => { // this.bot.off("physicsTick", listener); // this.bot.setControlState("back", false); // this.bot.setControlState("forward", true); // this.bot.setControlState("sprint", true); // } // this.bot.on("physicsTick", listener); do { this.bot.setControlState("forward", false); this.bot.setControlState("sprint", false); this.bot.setControlState("back", true); const looking = (0, mathUtils_1.movingAt)(this.target.position, this.bot.entity.position, // this.options.genericConfig.enemyReach (_a = this.bot.tracker.getEntitySpeed(this.target)) !== null && _a !== void 0 ? _a : new vec3_1.Vec3(0, 0, 0), PIOver3); if (!looking && this.wasInRange) break; yield this.bot.waitForTicks(1); } while (this.botReach() < this.options.genericConfig.attackRange + 0.1); this.bot.setControlState("back", false); this.bot.setControlState("forward", true); this.bot.setControlState("sprint", true); break; default: break; } }); } toggleShield() { return __awaiter(this, void 0, void 0, function* () { if (this.ticksToNextAttack !== 0 || !this.target || !this.wasInRange || !this.wasVisible) return false; const shield = this.shieldEquipped(); const wasShieldActive = shield; this.clearShieldToggleListener(); if (wasShieldActive && this.options.shieldConfig.enabled && this.options.shieldConfig.mode === "legit") { this.bot.deactivateItem(); } this.shieldToggleListener = (entity) => __awaiter(this, void 0, void 0, function* () { this.clearShieldToggleListener(); yield this.bot.waitForTicks(3); if (wasShieldActive && this.options.shieldConfig.enabled && this.options.shieldConfig.mode === "legit") { this.bot.activateItem(true); } else if (!this.bot.util.entity.isOffHandActive() && shield && this.options.shieldConfig.mode === "blatant") { this.bot.activateItem(true); } }); this.on("attackedTarget", this.shieldToggleListener); // await once(this.bot, "attackedTarget"); }); } rotate() { if (!this.options.rotateConfig.enabled || !this.target) return false; if (!this.options.rotateConfig.lookAtHidden && !this.wasVisible) return false; const pos = this.target.position.offset(0, this.target.height, 0); const lookFunc = this.options.rotateConfig.smooth ? this.bot.smoothLook.lookAt.bind(this.bot.smoothLook) : this.bot.lookAt.bind(this.bot); if (this.options.rotateConfig.mode === "constant") { lookFunc(pos); return; } else { if (this.ticksToNextAttack !== -1) return; switch (this.options.rotateConfig.mode) { case "legit": lookFunc(pos); break; case "instant": this.bot.lookAt(pos, true); break; case "silent": this.bot.util.move.forceLookAt(pos); break; case "ignore": break; default: break; } } } reactionaryCrit(noTickLimit = false) { var _a; return __awaiter(this, void 0, void 0, function* () { if (!this.options.critConfig.reaction.enabled) return; if (!this.target) return; if (this.tickOverride) return; this.tickOverride = true; let i = 0; for (; i < 12; i++) { yield this.bot.waitForTicks(1); if (this.bot.entity.onGround) { this.tickOverride = false; return; } if (this.options.critConfig.reaction.maxWaitDistance) { if (this.botReach() >= this.options.critConfig.reaction.maxWaitDistance) { this.tickOverride = false; return; } } if (this.bot.entity.velocity.y <= -0.25 && this.ticksToNextAttack <= -1 + ((_a = this.options.critConfig.reaction.maxPreemptiveTicks) !== null && _a !== void 0 ? _a : 0)) { break; } if (this.options.critConfig.reaction.maxWaitTicks && !noTickLimit) { if (this.ticksToNextAttack <= -1 - this.options.critConfig.reaction.maxWaitTicks) { break; } } } this.bot.setControlState("sprint", false); yield this.attemptAttack("reaction"); this.tickOverride = false; }); } attemptAttack(reason) { return __awaiter(this, void 0, void 0, function* () { // console.log("called attack:", reason, this.wasInRange, this.bot.getControlState("sprint"), this.bot.entity.velocity.y); if (!this.target) return; if (!this.wasInRange) { this.willBeFirstHit = true; return; } if (!this.options.genericConfig.hitThroughWalls && !this.wasVisible) return; if (Math.random() < this.options.genericConfig.missChancePerTick) { // this.timeToNextAttack = 0; yield this.bot.waitForTicks(1); yield this.attemptAttack(reason); return; } (0, util_1.attack)(this.bot, this.target); this.willBeFirstHit = false; this.emit("attackedTarget", this.target, reason, this.ticksToNextAttack); this.ticksToNextAttack = this.meleeAttackRate.getTicks(this.bot.heldItem); }); } shieldEquipped() { if (this.bot.supportFeature("doesntHaveOffHandSlot")) return false; const slot = this.bot.inventory.slots[this.bot.getEquipmentDestSlot("off-hand")]; if (!slot) return false; return slot.name.includes("shield"); } } exports.SwordPvp = SwordPvp;