Add player knockback on punch to builtin
authorsfan5 <sfan5@live.de>
Tue, 16 Jul 2019 17:20:06 +0000 (19:20 +0200)
committersfan5 <sfan5@live.de>
Sat, 10 Aug 2019 17:44:27 +0000 (19:44 +0200)
builtin/game/init.lua
builtin/game/knockback.lua [new file with mode: 0644]
doc/lua_api.txt

index 271e49be3a51386efbfa70bdf1ac7fcc4791a0e2..1d62be019d4543848c6aaa1cf5f7f1212983aa60 100644 (file)
@@ -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 (file)
index 0000000..b5c4cbc
--- /dev/null
@@ -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)
index 9fd2ba3f597e0fe38408438f9a24d538aa961f9b..6506dc2b21de0a10afb45b4b0971d9bd58e24c66 100644 (file)
@@ -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