diff options
-rw-r--r-- | builtin/game/init.lua | 1 | ||||
-rw-r--r-- | builtin/game/knockback.lua | 46 | ||||
-rw-r--r-- | doc/lua_api.txt | 9 |
3 files changed, 56 insertions, 0 deletions
diff --git a/builtin/game/init.lua b/builtin/game/init.lua index 271e49be3..1d62be019 100644 --- a/builtin/game/init.lua +++ b/builtin/game/init.lua @@ -33,5 +33,6 @@ dofile(gamepath .. "features.lua") dofile(gamepath .. "voxelarea.lua") dofile(gamepath .. "forceloading.lua") dofile(gamepath .. "statbars.lua") +dofile(gamepath .. "knockback.lua") profiler = nil diff --git a/builtin/game/knockback.lua b/builtin/game/knockback.lua new file mode 100644 index 000000000..b5c4cbc5a --- /dev/null +++ b/builtin/game/knockback.lua @@ -0,0 +1,46 @@ +-- can be overriden by mods +function core.calculate_knockback(player, hitter, time_from_last_punch, tool_capabilities, dir, distance, damage) + if damage == 0 or player:get_armor_groups().immortal then + return 0.0 + end + + local m = 8 + -- solve m - m*e^(k*4) = 4 for k + local k = -0.17328 + local res = m - m * math.exp(k * damage) + + if distance < 2.0 then + res = res * 1.1 -- more knockback when closer + elseif distance > 4.0 then + res = res * 0.9 -- less when far away + end + return res +end + +local function vector_absmax(v) + local max, abs = math.max, math.abs + return max(max(abs(v.x), abs(v.y)), abs(v.z)) +end + +core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, unused_dir, damage) + if player:get_hp() == 0 then + return -- RIP + end + + -- Server::handleCommand_Interact() adds eye offset to one but not the other + -- so the direction is slightly off, calculate it ourselves + local dir = vector.subtract(player:get_pos(), hitter:get_pos()) + local d = vector.length(dir) + if d ~= 0.0 then + dir = vector.divide(dir, d) + end + + local k = core.calculate_knockback(player, hitter, time_from_last_punch, tool_capabilities, dir, d, damage) + + local kdir = vector.multiply(dir, k) + if vector_absmax(kdir) < 1.0 then + return -- barely noticeable, so don't even send + end + + player:add_player_velocity(kdir) +end) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 9fd2ba3f5..6506dc2b2 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -5019,6 +5019,15 @@ Misc. of the creative mode setting, checks for "sneak" to set the `invert_wall` parameter and `prevent_after_place` set to `true`. +* `minetest.calculate_knockback(player, hitter, time_from_last_punch, + tool_capabilities, dir, distance, damage)` + * Returns the amount of knockback applied on the punched player. + * Arguments are equivalent to `register_on_punchplayer`, except the following: + * `distance`: distance between puncher and punched player + * This function can be overriden by mods that wish to modify this behaviour. + * You may want to cache and call the old function to allow multiple mods to + change knockback behaviour. + * `minetest.forceload_block(pos[, transient])` * forceloads the position `pos`. * returns `true` if area could be forceloaded |