feat(skill): combat

This commit is contained in:
RainbowBird
2025-01-08 23:28:21 +08:00
parent 3e92b1e945
commit 6baa188891
+25 -25
View File
@@ -1,24 +1,30 @@
import type { Entity } from 'prismarine-entity'
import type { Item } from 'prismarine-item'
import type { SkillContext } from './base'
import pathfinderModel from 'mineflayer-pathfinder'
import * as world from '../composables/world'
import * as mc from '../utils/mcdata'
import { log } from './base'
/**
* Equip the item with highest attack damage
*/
const { goals } = pathfinderModel
interface WeaponItem extends Item {
attackDamage: number
}
async function equipHighestAttack(ctx: SkillContext): Promise<void> {
const { bot } = ctx
const weapons = bot.inventory.items().filter(item =>
item.name.includes('sword')
|| (item.name.includes('axe') && !item.name.includes('pickaxe')),
)
) as WeaponItem[]
if (weapons.length === 0) {
const tools = bot.inventory.items().filter(item =>
item.name.includes('pickaxe')
|| item.name.includes('shovel'),
)
) as WeaponItem[]
if (tools.length === 0)
return
@@ -35,16 +41,13 @@ async function equipHighestAttack(ctx: SkillContext): Promise<void> {
await bot.equip(weapon, 'hand')
}
/**
* Attack the nearest mob of the given type
*/
export async function attackNearest(
ctx: SkillContext,
mobType: string,
kill = true,
): Promise<boolean> {
const { bot } = ctx
const mob = world.getNearbyEntities(bot, 24).find(entity => entity.name === mobType)
const worldCtx = world.createWorldContext(ctx.botCtx)
const mob = world.getNearbyEntities(worldCtx, 24).find(entity => entity.name === mobType)
if (mob) {
return await attackEntity(ctx, mob, kill)
@@ -54,9 +57,6 @@ export async function attackNearest(
return false
}
/**
* Attack a specific entity
*/
export async function attackEntity(
ctx: SkillContext,
entity: Entity,
@@ -68,14 +68,16 @@ export async function attackEntity(
if (!kill) {
if (bot.entity.position.distanceTo(pos) > 5) {
await bot.pathfinder.goto(bot.pathfinder.goals.GoalNear(pos.x, pos.y, pos.z, 4))
const goal = new goals.GoalNear(pos.x, pos.y, pos.z, 4)
await bot.pathfinder.goto(goal)
}
await bot.attack(entity)
return true
}
bot.pvp.attack(entity)
while (world.getNearbyEntities(bot, 24).includes(entity)) {
const worldCtx = world.createWorldContext(ctx.botCtx)
while (world.getNearbyEntities(worldCtx, 24).includes(entity)) {
await new Promise(resolve => setTimeout(resolve, 1000))
if (ctx.shouldInterrupt) {
bot.pvp.stop()
@@ -87,13 +89,11 @@ export async function attackEntity(
return true
}
/**
* Defend against nearby hostile mobs
*/
export async function defendSelf(ctx: SkillContext, range = 9): Promise<boolean> {
const { bot } = ctx
let attacked = false
let enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), range)
const worldCtx = world.createWorldContext(ctx.botCtx)
let enemy = world.getNearestEntityWhere(worldCtx, entity => mc.isHostile(entity), range)
while (enemy) {
await equipHighestAttack(ctx)
@@ -101,17 +101,17 @@ export async function defendSelf(ctx: SkillContext, range = 9): Promise<boolean>
if (bot.entity.position.distanceTo(enemy.position) >= 4
&& enemy.name !== 'creeper' && enemy.name !== 'phantom') {
try {
await bot.pathfinder.goto(bot.pathfinder.goals.GoalFollow(enemy, 3.5), true)
const goal = new goals.GoalFollow(enemy, 3.5)
await bot.pathfinder.goto(goal)
}
catch { /* might error if entity dies, ignore */ }
}
if (bot.entity.position.distanceTo(enemy.position) <= 2) {
try {
const invertedGoal = bot.pathfinder.goals.GoalInvert(
bot.pathfinder.goals.GoalFollow(enemy, 2),
)
await bot.pathfinder.goto(invertedGoal, true)
const followGoal = new goals.GoalFollow(enemy, 2)
const invertedGoal = new goals.GoalInvert(followGoal)
await bot.pathfinder.goto(invertedGoal)
}
catch { /* might error if entity dies, ignore */ }
}
@@ -119,7 +119,7 @@ export async function defendSelf(ctx: SkillContext, range = 9): Promise<boolean>
bot.pvp.attack(enemy)
attacked = true
await new Promise(resolve => setTimeout(resolve, 500))
enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), range)
enemy = world.getNearestEntityWhere(worldCtx, entity => mc.isHostile(entity), range)
if (ctx.shouldInterrupt) {
bot.pvp.stop()