Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PrismarineJS
GitHub Repository: PrismarineJS/mineflayer
Path: blob/master/lib/plugins/explosion.js
1467 views
1
const { Vec3 } = require('vec3')
2
3
module.exports = inject
4
5
// https://minecraft.wiki/w/Explosion
6
function calcExposure (playerPos, explosionPos, world) {
7
const dx = 1 / (0.6 * 2 + 1)
8
const dy = 1 / (1.8 * 2 + 1)
9
const dz = 1 / (0.6 * 2 + 1)
10
11
const d3 = (1 - Math.floor(1 / dx) * dx) / 2
12
const d4 = (1 - Math.floor(1 / dz) * dz) / 2
13
14
let sampled = 0
15
let exposed = 0
16
const pos = new Vec3(0, 0, 0)
17
for (pos.y = playerPos.y; pos.y <= playerPos.y + 1.8; pos.y += 1.8 * dy) {
18
for (pos.x = playerPos.x - 0.3 + d3; pos.x <= playerPos.x + 0.3; pos.x += 0.6 * dx) {
19
for (pos.z = playerPos.z - 0.3 + d4; pos.z <= playerPos.z + 0.3; pos.z += 0.6 * dz) {
20
const dir = pos.minus(explosionPos)
21
const range = dir.norm()
22
if (world.raycast(explosionPos, dir.normalize(), range) === null) {
23
exposed++
24
}
25
sampled++
26
}
27
}
28
}
29
return exposed / sampled
30
}
31
32
// https://minecraft.wiki/w/Armor#Damage_protection
33
function getDamageAfterAbsorb (damages, armorValue, toughness) {
34
const var3 = 2 + toughness / 4
35
const var4 = Math.min(Math.max(armorValue - damages / var3, armorValue * 0.2), 20)
36
return damages * (1 - var4 / 25)
37
}
38
39
// https://minecraft.wiki/w/Attribute#Operations
40
function getAttributeValue (prop) {
41
let X = prop.value
42
for (const mod of prop.modifiers) {
43
if (mod.operation !== 0) continue
44
X += mod.amount
45
}
46
let Y = X
47
for (const mod of prop.modifiers) {
48
if (mod.operation !== 1) continue
49
Y += X * mod.amount
50
}
51
for (const mod of prop.modifiers) {
52
if (mod.operation !== 2) continue
53
Y += Y * mod.amount
54
}
55
return Y
56
}
57
58
function inject (bot) {
59
const damageMultiplier = 7 // for 1.12+ 8 for 1.8 TODO check when the change occur (likely 1.9)
60
const armorThoughnessKey = 'generic.armorToughness' // was renamed in 1.16
61
62
const difficultyValues = {
63
peaceful: 0,
64
easy: 1,
65
normal: 2,
66
hard: 3
67
}
68
69
bot.getExplosionDamages = (targetEntity, sourcePos, power, rawDamages = false) => {
70
const distance = targetEntity.position.distanceTo(sourcePos)
71
const radius = 2 * power
72
if (distance >= radius) return 0
73
const exposure = calcExposure(targetEntity.position, sourcePos, bot.world)
74
const impact = (1 - distance / radius) * exposure
75
let damages = Math.floor((impact * impact + impact) * damageMultiplier * power + 1)
76
77
// The following modifiers are constant for the input targetEntity and doesnt depend
78
// on the source position, so if the goal is to compare between positions they can be
79
// ignored to save computations
80
if (!rawDamages && targetEntity.attributes['generic.armor']) {
81
const armor = getAttributeValue(targetEntity.attributes['generic.armor'])
82
const armorToughness = getAttributeValue(targetEntity.attributes[armorThoughnessKey])
83
damages = getDamageAfterAbsorb(damages, armor, armorToughness)
84
85
// TODO: protection enchantment and resistance effects
86
87
if (targetEntity.type === 'player') damages *= difficultyValues[bot.game.difficulty] * 0.5
88
} else if (!rawDamages && !targetEntity.attributes['generic.armor']) {
89
return null
90
}
91
return Math.floor(damages)
92
}
93
}
94
95