knockback.lua 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. -- can be overridden by mods
  2. function core.calculate_knockback(player, hitter, time_from_last_punch, tool_capabilities, dir, distance, damage)
  3. if damage == 0 or player:get_armor_groups().immortal then
  4. return 0.0
  5. end
  6. local m = 8
  7. -- solve m - m*e^(k*4) = 4 for k
  8. local k = -0.17328
  9. local res = m - m * math.exp(k * damage)
  10. if distance < 2.0 then
  11. res = res * 1.1 -- more knockback when closer
  12. elseif distance > 4.0 then
  13. res = res * 0.9 -- less when far away
  14. end
  15. return res
  16. end
  17. local function vector_absmax(v)
  18. local max, abs = math.max, math.abs
  19. return max(max(abs(v.x), abs(v.y)), abs(v.z))
  20. end
  21. core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, unused_dir, damage)
  22. if player:get_hp() == 0 then
  23. return -- RIP
  24. end
  25. -- Server::handleCommand_Interact() adds eye offset to one but not the other
  26. -- so the direction is slightly off, calculate it ourselves
  27. local dir = vector.subtract(player:get_pos(), hitter:get_pos())
  28. local d = vector.length(dir)
  29. if d ~= 0.0 then
  30. dir = vector.divide(dir, d)
  31. end
  32. local k = core.calculate_knockback(player, hitter, time_from_last_punch, tool_capabilities, dir, d, damage)
  33. local kdir = vector.multiply(dir, k)
  34. if vector_absmax(kdir) < 1.0 then
  35. return -- barely noticeable, so don't even send
  36. end
  37. player:add_velocity(kdir)
  38. end)