94 lines
3.1 KiB
JavaScript
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)
|
||
|
}
|
||
|
}
|