diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp
index add7c6a32..6cd16d300 100644
--- a/game/world/objects/npc.cpp
+++ b/game/world/objects/npc.cpp
@@ -2299,13 +2299,16 @@ void Npc::tickRegen(int32_t& v, const int32_t max, const int32_t chg, const uint
uint64_t tick = owner.tickCount();
if(tick
0 ? 1 : -1;
+ const int32_t n = int32_t((tick%period+dt)/period);
+ if(n==0)
+ return;
- int32_t nextV = std::max(0,std::min(v+val1-val0,max));
+ int32_t nextV = std::max(0,std::min(v+n*step,max));
if(v!=nextV) {
v = nextV;
// check health, in case of negative chg
@@ -4669,7 +4672,10 @@ bool Npc::canRayHitPoint(const Tempest::Vec3 self, const Tempest::Vec3 pos, floa
return !w->ray(self, pos).hasCol;
}
- float dx = self.x-pos.x, dz=self.z-pos.z;
+ // measure view cone from npc position, not from head bone: in melee the head of an
+ // attacking monster dives into the target and the direction becomes numerical noise.
+ // L'Hiver anti-exploit scripts read this as "player ran away" and heal the monster
+ float dx = x-pos.x, dz = z-pos.z;
float dir = angleDir(dx,dz);
float da = float(M_PI)*(visual.viewDirection()-dir)/180.f;
auto ca = angOverride > 0 ? std::cos(angOverride*M_PI/180.0) : ref;