|
| 1 | +-- can be overriden 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 | + |
| 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 |
| 18 | +end |
| 19 | + |
| 20 | +local 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)) |
| 23 | +end |
| 24 | + |
| 25 | +core.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_player_velocity(kdir) |
| 46 | +end) |
0 commit comments