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