Skip to content

Commit 5833d73

Browse files
committed
unification of damage and explosion utils
1 parent e713622 commit 5833d73

File tree

5 files changed

+171
-238
lines changed

5 files changed

+171
-238
lines changed

common/src/main/kotlin/com/lambda/module/modules/combat/AutoDisconnect.kt

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import com.lambda.sound.SoundManager.playSound
2828
import com.lambda.util.Communication
2929
import com.lambda.util.Communication.prefix
3030
import com.lambda.util.Formatting.string
31-
import com.lambda.util.combat.Explosion.explosionDamage
31+
import com.lambda.util.combat.CombatUtils.explosionDamage
32+
import com.lambda.util.combat.CombatUtils.hasDeadlyCrystal
3233
import com.lambda.util.player.SlotUtils.combined
3334
import com.lambda.util.text.*
3435
import com.lambda.util.world.fastEntitySearch
@@ -232,18 +233,11 @@ object AutoDisconnect : Module(
232233
}
233234
}),
234235
END_CRYSTAL({ crystals }, {
235-
fastEntitySearch<EndCrystalEntity>(10.2).find {
236-
player.health - explosionDamage(it.pos, player, 6.0) <= 1.0
237-
}?.let { crystal ->
238-
val damage = explosionDamage(crystal.pos, player, 6.0)
236+
if (hasDeadlyCrystal(1.0))
239237
buildText {
240-
literal("An end crystal at ")
241-
highlighted(crystal.pos.string)
242-
literal(" could give you ")
243-
highlighted("$damage")
244-
literal(" damage what would kill you!")
238+
literal("There was an end crystal close to you that would've killed you")
245239
}
246-
}
240+
else null
247241
});
248242
}
249-
}
243+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.util.combat
19+
20+
import com.lambda.context.SafeContext
21+
import com.lambda.core.annotations.InternalApi
22+
import com.lambda.util.math.VecUtils.dist
23+
import com.lambda.util.math.VecUtils.minus
24+
import com.lambda.util.math.VecUtils.times
25+
import com.lambda.util.math.VecUtils.vec3d
26+
import com.lambda.util.world.WorldUtils.internalGetFastEntities
27+
import com.lambda.util.world.fastEntitySearch
28+
import com.lambda.util.world.toFastVec
29+
import net.minecraft.enchantment.EnchantmentHelper
30+
import net.minecraft.enchantment.ProtectionEnchantment
31+
import net.minecraft.entity.LivingEntity
32+
import net.minecraft.entity.damage.DamageSource
33+
import net.minecraft.entity.decoration.EndCrystalEntity
34+
import net.minecraft.entity.effect.StatusEffects
35+
import net.minecraft.registry.tag.DamageTypeTags
36+
import net.minecraft.util.math.Vec3d
37+
import net.minecraft.util.math.Vec3i
38+
import net.minecraft.world.explosion.Explosion
39+
import kotlin.math.max
40+
import kotlin.math.min
41+
42+
object CombatUtils {
43+
/**
44+
* Scales damage up or down based on the player resistances and other variables
45+
*
46+
* @param entity The entity to calculate the damage for
47+
* @param damage The damage to apply
48+
*/
49+
fun DamageSource.scale(entity: LivingEntity, damage: Double): Double {
50+
if (entity.blockedByShield(this)) return 0.0
51+
val resistanceAmplifier = entity.getStatusEffect(StatusEffects.RESISTANCE)?.amplifier ?: -1
52+
53+
if (isIn(DamageTypeTags.BYPASSES_EFFECTS)) return damage
54+
55+
if (entity.hasStatusEffect(StatusEffects.RESISTANCE) && !isIn(DamageTypeTags.BYPASSES_RESISTANCE))
56+
return (damage - max(damage * (25 - (resistanceAmplifier + 1) * 5) / 25.0, 0.0)).coerceAtLeast(0.0)
57+
58+
if (isIn(DamageTypeTags.BYPASSES_ENCHANTMENTS)) return damage
59+
60+
val protectionAmount = EnchantmentHelper.getProtectionAmount(entity.armorItems, this)
61+
if (protectionAmount > 0) return damage * (1.0 - min(protectionAmount, 20) / 25.0)
62+
63+
return damage
64+
}
65+
66+
/**
67+
* Returns whether there is a deadly end crystal in proximity of the player
68+
*
69+
* @param minHealth The minimum health (in half hearts) at which an explosion is considered deadly
70+
*/
71+
fun SafeContext.hasDeadlyCrystal(minHealth: Double) =
72+
fastEntitySearch<EndCrystalEntity>(12.0)
73+
.any { player.health - explosionDamage(it.pos, player, 6.0) <= minHealth}
74+
75+
/**
76+
* Calculates the damage dealt by an explosion to a living entity
77+
*
78+
* @param source The source of the explosion
79+
* @param entity The entity to calculate the damage for
80+
*/
81+
fun SafeContext.explosionDamage(source: Explosion, entity: LivingEntity) =
82+
explosionDamage(source.position, entity, source.power.toDouble())
83+
84+
/**
85+
* Calculates the damage dealt by an explosion to a living entity
86+
*
87+
* @param position The position of the explosion
88+
* @param entity The entity to calculate the damage for
89+
* @param power The [power of the explosion](https://minecraft.wiki/w/Explosion#Damage)
90+
*/
91+
fun SafeContext.explosionDamage(position: Vec3i, entity: LivingEntity, power: Double): Double =
92+
explosionDamage(position.vec3d, entity, power)
93+
94+
/**
95+
* Calculates the damage dealt by an explosion to a living entity.
96+
*
97+
* @param position The position of the explosion
98+
* @param entity The entity to calculate the damage for
99+
* @param power The [power of the explosion](https://minecraft.wiki/w/Explosion#Damage)
100+
*/
101+
fun SafeContext.explosionDamage(position: Vec3d, entity: LivingEntity, power: Double): Double {
102+
val distance = entity dist position
103+
104+
val impact = (1.0 - distance / (power * 2.0)) * Explosion.getExposure(position, entity) * 0.4
105+
val damage = world.difficulty.id * 3 * power * (impact * impact + impact) + 1
106+
107+
return Explosion.createDamageSource(world, null).scale(entity, damage)
108+
}
109+
110+
/**
111+
* Calculates the velocity of entities in the explosion
112+
*
113+
* @param explosion The explosion to calculate the velocity for
114+
*/
115+
@OptIn(InternalApi::class)
116+
fun SafeContext.explosionVelocity(explosion: Explosion): Map<LivingEntity, Vec3d> {
117+
val ref = ArrayList<LivingEntity>()
118+
internalGetFastEntities(explosion.position.toFastVec(), explosion.power * 2.0, ref)
119+
return ref.associateWith { entity -> explosionVelocity(entity, explosion) }
120+
}
121+
122+
/**
123+
* Calculates the velocity of a living entity affected by an explosion
124+
*
125+
* @param entity The entity to calculate the velocity for
126+
* @param explosion The explosion to calculate the velocity for
127+
*/
128+
fun SafeContext.explosionVelocity(entity: LivingEntity, explosion: Explosion) =
129+
explosionVelocity(entity, explosion.position, explosion.power.toDouble())
130+
131+
/**
132+
* Calculates the velocity of a living entity affected by an explosion
133+
*
134+
* @param entity The entity to calculate the velocity for
135+
* @param position The position of the explosion
136+
* @param power The strength of the explosion
137+
*/
138+
fun SafeContext.explosionVelocity(entity: LivingEntity, position: Vec3d, power: Double): Vec3d {
139+
val distance = entity.pos.distanceTo(position)
140+
141+
val size = power * 2.0
142+
val vel = ProtectionEnchantment.transformExplosionKnockback(
143+
entity,
144+
(1.0 - distance / size) * Explosion.getExposure(position, entity)
145+
)
146+
147+
val diff = entity.eyePos - position
148+
return diff.normalize() * vel
149+
}
150+
}

common/src/main/kotlin/com/lambda/util/combat/Damage.kt

Lines changed: 0 additions & 50 deletions
This file was deleted.

0 commit comments

Comments
 (0)