LookAtMySuitBot/js/node_modules/mineflayer/lib/plugins/explosion.js

94 lines
3.1 KiB
JavaScript

const { Vec3 } = require('vec3')
module.exports = inject
// https://minecraft.fandom.com/wiki/Explosion
function calcExposure (playerPos, explosionPos, world) {
const dx = 1 / (0.6 * 2 + 1)
const dy = 1 / (1.8 * 2 + 1)
const dz = 1 / (0.6 * 2 + 1)
const d3 = (1 - Math.floor(1 / dx) * dx) / 2
const d4 = (1 - Math.floor(1 / dz) * dz) / 2
let sampled = 0
let exposed = 0
const pos = new Vec3(0, 0, 0)
for (pos.y = playerPos.y; pos.y <= playerPos.y + 1.8; pos.y += 1.8 * dy) {
for (pos.x = playerPos.x - 0.3 + d3; pos.x <= playerPos.x + 0.3; pos.x += 0.6 * dx) {
for (pos.z = playerPos.z - 0.3 + d4; pos.z <= playerPos.z + 0.3; pos.z += 0.6 * dz) {
const dir = pos.minus(explosionPos)
const range = dir.norm()
if (world.raycast(explosionPos, dir.normalize(), range) === null) {
exposed++
}
sampled++
}
}
}
return exposed / sampled
}
// https://minecraft.fandom.com/wiki/Armor#Damage_protection
function getDamageAfterAbsorb (damages, armorValue, toughness) {
const var3 = 2 + toughness / 4
const var4 = Math.min(Math.max(armorValue - damages / var3, armorValue * 0.2), 20)
return damages * (1 - var4 / 25)
}
// https://minecraft.fandom.com/wiki/Attribute#Operations
function getAttributeValue (prop) {
let X = prop.value
for (const mod of prop.modifiers) {
if (mod.operation !== 0) continue
X += mod.amount
}
let Y = X
for (const mod of prop.modifiers) {
if (mod.operation !== 1) continue
Y += X * mod.amount
}
for (const mod of prop.modifiers) {
if (mod.operation !== 2) continue
Y += Y * mod.amount
}
return Y
}
function inject (bot) {
const damageMultiplier = 7 // for 1.12+ 8 for 1.8 TODO check when the change occur (likely 1.9)
const armorThoughnessKey = 'generic.armorToughness' // was renamed in 1.16
const difficultyValues = {
peaceful: 0,
easy: 1,
normal: 2,
hard: 3
}
bot.getExplosionDamages = (targetEntity, sourcePos, power, rawDamages = false) => {
const distance = targetEntity.position.distanceTo(sourcePos)
const radius = 2 * power
if (distance >= radius) return 0
const exposure = calcExposure(targetEntity.position, sourcePos, bot.world)
const impact = (1 - distance / radius) * exposure
let damages = Math.floor((impact * impact + impact) * damageMultiplier * power + 1)
// The following modifiers are constant for the input targetEntity and doesnt depend
// on the source position, so if the goal is to compare between positions they can be
// ignored to save computations
if (!rawDamages && targetEntity.attributes['generic.armor']) {
const armor = getAttributeValue(targetEntity.attributes['generic.armor'])
const armorToughness = getAttributeValue(targetEntity.attributes[armorThoughnessKey])
damages = getDamageAfterAbsorb(damages, armor, armorToughness)
// TODO: protection enchantment and resistance effects
if (targetEntity.type === 'player') damages *= difficultyValues[bot.game.difficulty] * 0.5
} else if (!rawDamages && !targetEntity.attributes['generic.armor']) {
return null
}
return Math.floor(damages)
}
}