pvp_revamped/punch.lua

822 lines
30 KiB
Lua

local head_height = pvp_revamped.config.head_height
local torso_height = pvp_revamped.config.torso_height
local leg_height = pvp_revamped.config.leg_height
local knee_height = pvp_revamped.config.knee_height
local disarm_chance_mul = pvp_revamped.config.disarm_chance_mul
local leg_immobilize_mul = pvp_revamped.config.leg_immobilize_mul
local knee_immobilize_mul = pvp_revamped.config.knee_immobilize_mul
local immobilize_mul = pvp_revamped.config.immobilize_mul
local block_wear_mul = pvp_revamped.config.block_wear_mul
local head_dmg_mul = pvp_revamped.config.head_dmg_mul
local torso_dmg_mul = pvp_revamped.config.torso_dmg_mul
local arm_dmg_mul = pvp_revamped.config.arm_dmg_mul
local leg_dmg_mul = pvp_revamped.config.leg_dmg_mul
local front_dmg_mul = pvp_revamped.config.front_dmg_mul
local side_dmg_mul = pvp_revamped.config.side_dmg_mul
local back_dmg_mul = pvp_revamped.config.back_dmg_mul
local elevated_dmg_mul = pvp_revamped.config.elevated_dmg_mul
local equal_height_dmg_mul = pvp_revamped.config.equal_height_dmg_mul
local lower_elevation_dmg_mul = pvp_revamped.config.lower_elevation_dmg_mul
local velocity_dmg_mul = pvp_revamped.config.velocity_dmg_mul
local optimal_distance_dmg_mul = pvp_revamped.config.optimal_distance_dmg_mul
local maximum_distance_dmg_mul = pvp_revamped.config.maximum_distance_dmg_mul
local optimal_distance_mul = pvp_revamped.config.optimal_distance_mul
local parry_dmg_mul = pvp_revamped.config.parry_dmg_mul
local counter_dmg_mul = pvp_revamped.config.counter_dmg_mul
local counter_duration = pvp_revamped.config.counter_duration
local clash_duration = pvp_revamped.config.clash_duration
local get_player_data = pvp_revamped.get_player_data
local player_data = pvp_revamped.player_data
local player_persistent_data = pvp_revamped.player_persistent_data
local hit_points = pvp_revamped.hit_points
local create_hud_text_center = pvp_revamped.create_hud_text_center
local remove_text_center = pvp_revamped.remove_text_center
local point_arm = pvp_revamped.point_arm
local registered_tools = minetest.registered_tools
local raycast = minetest.raycast
local get_us_time = minetest.get_us_time
local get_player_information = minetest.get_player_information
local add_item = minetest.add_item
local get_inventory = minetest.get_inventory
local armor_3d = minetest.global_exists("armor")
local insert = table.insert
local add = vector.add
local multiply = vector.multiply
local subtract = vector.subtract
local distance = vector.distance
local cos = math.cos
local sin = math.sin
local abs = math.abs
local atan = math.atan
local random = math.random
local max = math.max
local min = math.min
local floor = math.floor
local pi = math.pi
local rad90 = pi * 0.5
local rad360 = pi * 2
-- Do the damage calculations when the player gets hit.
local function punch(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
local name = player:get_player_name()
local victim_data = get_player_data(name)
-- If the player is dodging return true.
if victim_data.active_barrel_rolls or victim_data.active_dodges then
return true
end
local hitter_name = hitter:get_player_name()
local hitter_data = get_player_data(hitter_name)
local projectile_data = pvp_revamped.projectile_data
-- Cancel any attack if the hitter is in barrel_roll or dodge mode.
-- Or if the hitter is in the process of throwing.
if (hitter_data.active_barrel_rolls or hitter_data.active_dodges or hitter_data.throw) and not projectile_data then
return true
end
local pos1
local pos2 = player:get_pos()
local hitter_pos
local hitter_velocity
local item
local range = 4
local yaw = player:get_look_horizontal()
local front
local side
local arm
local leg
local knee
local re_yaw
local full_punch
local full_punch_interval = 1.4
local _dir
local projectile
local projectile_intersection_point
-- Use projectile_data if a thrown entity was the one that punched.
if projectile_data then
pos1 = projectile_data.pos
hitter_pos = {x = pos1.x, y = pos1.y, z = pos1.z}
item = registered_tools[projectile_data.name]
_dir = projectile_data.dir
hitter_velocity = projectile_data.velocity
projectile_intersection_point = projectile_data.intersection_point
projectile = true
-- Set the projectile table to nil.
projectile_data = nil
else
pos1 = hitter:get_pos()
hitter_pos = {x = pos1.x, y = pos1.y, z = pos1.z}
item = registered_tools[hitter:get_wielded_item():get_name()]
-- Raise the position to eye height.
hitter_pos.y = hitter_pos.y + hitter:get_properties().eye_height
_dir = hitter:get_look_dir()
hitter_velocity = hitter:get_player_velocity()
end
if item then
tool_capabilities = item.tool_capabilities
end
-- I got this rare error were tool_capabilities was nil so I put this here to safe guard.
if not tool_capabilities then
return true
end
if item and item.range then
range = item.range
end
local server_lag = get_player_information(name).avg_jitter
-- Get whether this is a full punch.
if tool_capabilities and time_from_last_punch >= tool_capabilities.full_punch_interval - server_lag then
full_punch = true
full_punch_interval = tool_capabilities.full_punch_interval
elseif tool_capabilities and tool_capabilities.full_punch_interval then
full_punch_interval = tool_capabilities.full_punch_interval
local spam_damage = tool_capabilities.spam_damage
if spam_damage then
damage = spam_damage
end
end
-- Get the second position from the direction of the hitter.
local hit_pos1 = add(hitter_pos, _dir)
local hit_pos2 = add(hit_pos1, multiply(_dir, range))
local ray = raycast(hit_pos1, hit_pos2)
local function hit(intersection_point)
local newpos = subtract(intersection_point, pos2)
local y1 = intersection_point.y
local y2 = pos2.y
-- Get the tool's modifiers or use the default ones.
local head_height = tool_capabilities.head_height or head_height
local torso_height = tool_capabilities.torso_height or torso_height
local leg_height = tool_capabilities.leg_height or leg_height
local knee_height = tool_capabilities.knee_height or knee_height
local head_dmg_mul = tool_capabilities.head_dmg_mul or head_dmg_mul
local torso_dmg_mul = tool_capabilities.torso_dmg_mul or torso_dmg_mul
local arm_dmg_mul = tool_capabilities.arm_dmg_mul or arm_dmg_mul
local leg_dmg_mul = tool_capabilities.leg_dmg_mul or leg_dmg_mul
if head_height and head_dmg_mul and y1 > y2 + head_height then
-- If the player was hit in the head add extra damage.
damage = damage * head_dmg_mul
elseif torso_height and y1 > y2 + torso_height then
-- Find if the player was hit in the torso or arm.
local near_part = 0
local past_distance = -1
for _, point in pairs(hit_points) do
local x = point.x
local y = point.y
local z = point.z
local co = cos(yaw)
local si = sin(yaw)
local re_x = co * x - si * z
local re_z = si * x + co * z
local dist = distance(newpos, {x = re_x, y = y, z = re_z})
if dist < past_distance or past_distance == -1 then
past_distance = dist
near_part = point.part
end
end
if near_part == point_arm then
-- Hit in the arm.
arm = true
if arm_dmg_mul then
damage = damage * arm_dmg_mul
end
elseif torso_dmg_mul then
-- Hit in the torso.
damage = damage * torso_dmg_mul
end
elseif leg_height and y1 > y2 + leg_height then
-- Hit in the leg.
leg = true
if leg_dmg_mul then
damage = damage * leg_dmg_mul
end
elseif knee_height and y1 > y2 + knee_height then
-- Hit in the knee.
knee = true
if leg_dmg_mul then
damage = damage * leg_dmg_mul
end
else
-- Hit in the lower leg.
leg = true
if leg_dmg_mul then
damage = damage * leg_dmg_mul
end
end
local dist = distance(hitter_pos, pos2)
local optimal_distance_mul = tool_capabilities.optimal_distance_mul or optimal_distance_mul
local dist_rounded = dist + 0.5 - (dist + 0.5) % 1
-- If the distance rounded is outside the range skip.
if optimal_distance_mul and dist_rounded <= range + 1 then
local optimal_distance_dmg_mul = tool_capabilities.optimal_distance_dmg_mul or optimal_distance_dmg_mul
local maximum_distance_dmg_mul = tool_capabilities.maximum_distance_dmg_mul or maximum_distance_dmg_mul
local optimal_range = range * optimal_distance_mul
-- Add or remove damage based on the distance.
-- Full punches are not affected by any maximum distance.
if (not full_punch or maximum_distance_dmg_mul < 1.0) and maximum_distance_dmg_mul and dist_rounded > optimal_range then
damage = damage * maximum_distance_dmg_mul
elseif (not full_punch or optimal_distance_dmg_mul > 0.0) and optimal_distance_dmg_mul and dist_rounded < optimal_range then
damage = damage * optimal_distance_dmg_mul
end
end
-- Get the yaw from both the player and intersection point.
local yaw2 = atan(newpos.z / newpos.x) + rad90
if intersection_point.x >= pos2.x then
yaw2 = yaw2 + pi
end
re_yaw = rad360 - (yaw - yaw2)
if re_yaw < 0 then
re_yaw = rad360 - re_yaw
end
if re_yaw > rad360 then
re_yaw = re_yaw - rad360
end
local back_dmg_mul = tool_capabilities.back_dmg_mul or back_dmg_mul
if (re_yaw <= 0.7853982 and re_yaw >= 0) or (re_yaw <= 6.283185 and re_yaw >= 5.497787) then
-- Hit on the front.
front = true
local front_dmg_mul = tool_capabilities.front_dmg_mul or front_dmg_mul
if front_dmg_mul then
damage = damage * front_dmg_mul
end
elseif re_yaw <= 2.356194 then
-- Hit on the left-side.
side = true
local side_dmg_mul = tool_capabilities.side_dmg_mul or side_dmg_mul
if side_dmg_mul then
damage = damage * side_dmg_mul
end
elseif back_dmg_mul and re_yaw <= 3.926991 then
-- Hit on the back-side.
damage = damage * back_dmg_mul
else
-- Hit on the right-side.
side = true
local side_dmg_mul = tool_capabilities.side_dmg_mul or side_dmg_mul
if side_dmg_mul then
damage = damage * side_dmg_mul
end
end
-- You can only hit the knee-caps in the front.
if side and knee then
knee = nil
leg = true
end
end
if not projectile then
for pointed_thing in ray do
if pointed_thing.type == "object" and pointed_thing.ref:is_player() and pointed_thing.ref:get_player_name() == name then
hit(pointed_thing.intersection_point)
-- End the loop we got what we came for.
break
end
end
else
hit(projectile_intersection_point)
end
local elevated_dmg_mul = tool_capabilities.elevated_dmg_mul or elevated_dmg_mul
local lower_elevation_dmg_mul = tool_capabilities.lower_elevation_dmg_mul or lower_elevation_dmg_mul
local equal_height_dmg_mul = tool_capabilities.equal_height_dmg_mul or equal_height_dmg_mul
if elevated_dmg_mul and pos1.y > pos2.y then
-- Give a damage bonus or drawback to the aggressor if they are above the victim.
damage = damage * elevated_dmg_mul
elseif lower_elevation_dmg_mul and pos1.y < pos2.y then
-- Give a damage bonus or drawback to the aggressor if they are below the victim.
damage = damage * lower_elevation_dmg_mul
elseif equal_height_dmg_mul then
-- Give a damage bonus or drawback to the aggressor if they are equal footing with the victim.
damage = damage * equal_height_dmg_mul
end
-- This damage bonus can only be used if this is a full interval punch.
local velocity_dmg_mul = tool_capabilities.velocity_dmg_mul or velocity_dmg_mul
if full_punch and velocity_dmg_mul then
local vv
if front then
-- Ignore the victim's speed if you hit them in the front.
vv = max(abs(hitter_velocity.x), abs(hitter_velocity.y), abs(hitter_velocity.z))
else
-- Subtract the victim's velocity from the aggressor if they where not hit in the front.
local v2 = player:get_player_velocity()
vv = max(abs(hitter_velocity.x) - abs(v2.x), abs(hitter_velocity.y) - abs(v2.y), abs(hitter_velocity.z) - abs(v2.z))
end
if vv > 0 then
-- Give a damage bonus to the aggressor based on how fast they are running.
damage = damage + vv * velocity_dmg_mul
end
end
-- If damage is at or below zero set it to a default value.
damage = max(damage, 0.1)
if not projectile then
-- Remove the hitter's blocking data.
if hitter_data.block then
local on_block_deactivated = hitter_data.block.on_block_deactivated
-- Invoke deactivate block function if any.
if on_block_deactivated then
on_block_deactivated(player)
end
hitter_data.block = nil
-- Remove un-used hud element.
remove_text_center(hitter, "pvp_revamped:block_pool")
end
if hitter_data.shield then
on_block_deactivated = hitter_data.shield.on_block_deactivated
-- Invoke deactivate block function if any.
if on_block_deactivated then
on_block_deactivated(player)
end
hitter_data.shield = nil
-- Remove un-used hud element.
remove_text_center(hitter, "pvp_revamped:shield_pool")
end
player_data[hitter_name] = hitter_data
end
local data_throw = victim_data.throw
local data_block = victim_data.block
local hp = player:get_hp()
local wielded_item = player:get_wielded_item()
local item_name = wielded_item:get_name()
local block_wear_mul = tool_capabilities.block_wear_mul or block_wear_mul
server_lag = server_lag * 1000000
local timeframe = get_us_time() - server_lag
local hasty_guard_block = data_block and data_block.initial_time + data_block.hasty_guard_duration > timeframe
-- Process if the player is blocking with a tool or not.
if (front or hasty_guard_block) and
data_block and
not data_throw and
data_block.pool > 0 and
data_block.name == item_name then
-- Is hasty guard true?
if hasty_guard_block then
local on_hasty_guard = data_block.on_hasty_guard
if on_hasty_guard then
on_hasty_guard(player, hitter, damage)
end
-- End on punch if true.
return true
end
-- Block the damage and add it as wear to the tool.
wielded_item:add_wear(((damage - full_punch_interval) / 75) * block_wear_mul)
player:set_wielded_item(wielded_item)
local pool = data_block.pool
pool = pool - damage
-- Remove block table if pool is zero or below.
if pool <= 0 then
local on_guard_break = data_block.on_guard_break
-- Invoke deactivate block function if any.
if on_guard_break then
on_guard_break(player, hitter, damage)
end
victim_data.block = nil
-- Remove un-used hud element.
remove_text_center(player, "pvp_revamped:block_pool")
return true
end
local on_block_damage = data_block.on_block_damage
-- Run damage blocked function.
if on_block_damage then
on_block_damage(player, hitter, damage)
end
-- Update block pool text.
create_hud_text_center(player, "pvp_revamped:block_pool", pool)
data_block.pool = pool
victim_data.block = data_block
return true
end
local data_shield = victim_data.shield
local hasty_guard_shield = data_shield and data_shield.initial_time + data_shield.hasty_guard_duration > timeframe
-- Process if the player is blocking with a shield or not.
if data_shield and
not data_shield.armor_inv and
not data_throw and data_shield.pool > 0 and
data_shield.name == item_name and
(front or side or hasty_guard_shield) then
-- Is hasty guard true?
if hasty_guard_shield then
local on_hasty_guard = data_shield.on_hasty_guard
if on_hasty_guard then
on_hasty_guard(player, hitter, damage)
end
-- End on punch if true.
return true
end
-- Block the damage and add it as wear to the tool.
local axe_wear = 0
local pool = data_shield.pool
if tool_capabilities and tool_capabilities.damage_groups and tool_capabilities.damage_groups.shield then
axe_wear = tool_capabilities.damage_groups.shield
end
-- Wear down the shield plus axe damage.
wielded_item:add_wear((((damage - full_punch_interval) / 75) * block_wear_mul) + axe_wear)
player:set_wielded_item(wielded_item)
-- pool minus damage + axe_wear.
pool = pool - (damage + axe_wear)
-- Remove shield table if pool is zero or below.
if pool <= 0 then
local on_guard_break = data_shield.on_guard_break
-- Invoke guard break function if any.
if on_guard_break then
on_guard_break(player, hitter, damage)
end
victim_data.shield = nil
-- Remove un-used hud element.
remove_text_center(player, "pvp_revamped:shield_pool")
return true
end
local on_block_damage = data_shield.on_block_damage
-- Run damage blocked function.
if on_block_damage then
on_block_damage(player, hitter, damage)
end
-- Update shield pool text.
create_hud_text_center(player, "pvp_revamped:shield_pool", pool)
data_shield.pool = pool
victim_data.shield = data_shield
return true
elseif armor_3d and data_shield and data_shield.armor_inv and not data_throw and data_shield.pool > 0 and (front or side) then
local inv = get_inventory({type = "detached", name = name .. "_armor"})
if inv then
-- Block the damage and add it as wear to the tool.
local axe_wear = 0
local inventory_armor_shield = player_persistent_data[name].inventory_armor_shield
local index = inventory_armor_shield.index
local stack = inv:get_stack("armor", index)
if tool_capabilities and tool_capabilities.damage_groups and tool_capabilities.damage_groups.shield then
axe_wear = tool_capabilities.damage_groups.shield
end
if stack and stack:get_name() == inventory_armor_shield.name then
-- Is hasty guard true?
if hasty_guard_shield then
local on_hasty_guard = data_shield.on_hasty_guard
if on_hasty_guard then
on_hasty_guard(player, hitter, damage)
end
-- End on punch if true.
return true
end
local pool = data_shield.pool
-- Wear down the shield plus axe damage.
stack:add_wear((((damage - full_punch_interval) / 75) * block_wear_mul) + axe_wear)
inv:set_stack("armor", index, stack)
-- pool minus damage + axe_wear.
pool = pool - (damage + axe_wear)
-- Remove shield table if pool is zero or below.
if pool <= 0 then
local on_guard_break = data_shield.on_guard_break
-- Invoke guard break function if any.
if on_guard_break then
on_guard_break(player, hitter, damage)
end
victim_data.shield = nil
-- Remove un-used hud element.
remove_text_center(player, "pvp_revamped:shield_pool")
return true
end
local on_block_damage = data_shield.on_block_damage
-- Run damage blocked function.
if on_block_damage then
on_block_damage(player, hitter, damage)
end
-- Update shield pool text.
create_hud_text_center(player, "pvp_revamped:shield_pool", pool)
data_shield.pool = pool
victim_data.shield = data_shield
return true
else
-- Remove the data if we either can't find the stack or the name is different.
player_persistent_data[name].inventory_armor_shield = nil
end
else
-- No inv so remove data.
player_persistent_data[name].inventory_armor_shield = nil
end
end
-- Process if the player was hit in the arm.
if arm then
local item2 = registered_tools[item_name]
local chance
if item2 and not data_shield and not data_block and item2.tool_capabilities and item2.tool_capabilities.damage_groups.fleshy and item2.tool_capabilities.full_punch_interval then
-- Compute the chance to disarm by the victim's hp and tool stats.
local disarm_chance_mul = tool_capabilities.disarm_chance_mul or disarm_chance_mul
chance = random(0, ((hp + (item2.tool_capabilities.damage_groups.fleshy - item2.tool_capabilities.full_punch_interval) * disarm_chance_mul) - damage) + 1)
elseif not item2 and not data_shield and not data_block then
-- Compute the chance to disarm by the victim's hp.
chance = random(0, (hp - damage) + 1)
end
-- Disarm the player if chance equals zero.
if chance and chance <= 0 then
local drop_item = wielded_item:take_item()
local obj = add_item(pos2, drop_item)
if obj then
obj:get_luaentity().collect = true
end
player:set_wielded_item(wielded_item)
end
end
local function set_immobilize_data(speed, damage)
player:set_physics_override({speed = speed, jump = speed})
local immobilize_mul = tool_capabilities.immobilize_mul or immobilize_mul
victim_data.immobilize = {time = get_us_time(), value = damage * immobilize_mul}
end
-- Process if the player was hit in the leg.
if leg then
-- immobilize the player.
local leg_immobilize_mul = tool_capabilities.leg_immobilize_mul or leg_immobilize_mul
local dmg = max(damage - hp, 1)
local speed = min(1 / dmg * leg_immobilize_mul, 0.1)
local data_immobilize = victim_data.immobilize
if not data_immobilize or data_immobilize.value > speed then
set_immobilize_data(speed, dmg)
end
elseif knee then
-- immobilize the player.
local knee_immobilize_mul = tool_capabilities.knee_immobilize_mul or knee_immobilize_mul
local dmg = max(damage - hp, 1.5)
local speed = min(1 / dmg * knee_immobilize_mul, 0.1)
local data_immobilize = victim_data.immobilize
if data_immobilize then
-- Add the original value and update all immobilize data.
speed = min(abs(speed - data_immobilize.value), 0.1)
set_immobilize_data(speed, dmg)
else
set_immobilize_data(speed, dmg)
end
end
if player:get_properties().damage_texture_modifier == "" then
-- Revert the damage texture modifier.
player:set_properties{damage_texture_modifier = player_persistent_data[name].damage_texture_modifier}
end
-- If there is a damage queue for the hitter tigger the clash.
local hitter_hitdata = hitter_data.hit
local none = true
if item and item.on_hit then
item.on_hit(player, hitter, damage)
end
if hitter_hitdata then
server_lag = get_player_information(hitter_name).avg_jitter * 1000000
local count = #hitter_hitdata
for i = count, 1, -1 do
local hd = hitter_hitdata[i]
local active = hd.time + clash_duration + server_lag < get_us_time()
if hd.name == name and active then
if hd.parry then
-- Process parry attack.
damage = max(hd.damage - (damage + hd.c_damage) * hd.parry_dmg_mul, 0)
local on_parry = hd.on_parry
if on_parry then
on_parry(player, hitter, damage)
end
elseif full_punch and tool_capabilities.counter_duration and hd.time + tool_capabilities.counter_duration + server_lag > get_us_time() then
-- All damage gets reversed on counter.
-- Current damage gets added to it plus the damage multipliable.
local counter_dmg_mul = tool_capabilities.counter_dmg_mul or counter_dmg_mul
damage = hd.damage + (damage * counter_dmg_mul)
if item and item.on_counter then
item.on_counter(player, hitter, damage)
end
else
-- Reduce or, remove the damage and resolve the clash.
-- Negative damage will be applied to the hitter.
local c_damage = damage * tool_capabilities.clash_def_mul or 0
damage = max(hd.damage - (damage + c_damage), 0)
if item and item.on_clash then
item.on_clash(player, hitter, damage)
end
end
hitter_hitdata[i] = hitter_hitdata[count]
hitter_hitdata[count] = nil
none = nil
break
elseif not active then
hitter_hitdata[i] = hitter_hitdata[count]
hitter_hitdata[count] = nil
count = count - 1
end
end
end
if none and victim_data.hit then
local parry = floor(hitter:get_player_control_bits() / 256) % 2 == 1
local on_parry
if item and item.on_parry then
on_parry = item.on_parry
end
local data = {
name = hitter_name,
damage = damage,
parry = parry,
on_parry = on_parry,
time = get_us_time()
}
if parry then
data.parry_dmg_mul = tool_capabilities.parry_dmg_mul or parry_dmg_mul
data.c_damage = damage * tool_capabilities.clash_def_mul or 0
damage = 0
end
insert(victim_data.hit, 1, data)
if item and item.on_first_hit then
item.on_first_hit(player, hitter, damage)
end
elseif none then
local parry = floor(hitter:get_player_control_bits() / 256) % 2 == 1
local on_parry
if item and item.on_parry then
on_parry = item.on_parry
end
local data = {
name = hitter_name,
damage = damage,
parry = parry,
on_parry = on_parry,
time = get_us_time()
}
if parry then
data.parry_dmg_mul = tool_capabilities.parry_dmg_mul or parry_dmg_mul
data.c_damage = damage * tool_capabilities.clash_def_mul or 0
damage = 0
end
victim_data.hit = {data}
if item and item.on_first_hit then
item.on_first_hit(player, hitter, damage)
end
end
if victim_data.block then
local on_block_deactivated = victim_data.block.on_block_deactivated
-- Invoke deactivate block function if any.
if on_block_deactivated then
on_block_deactivated(player)
end
victim_data.block = nil
-- Remove un-used hud element.
remove_text_center(player, "pvp_revamped:block_pool")
end
if victim_data.shield then
on_block_deactivated = victim_data.shield.on_block_deactivated
-- Invoke deactivate block function if any.
if on_block_deactivated then
on_block_deactivated(player)
end
victim_data.shield = nil
-- Remove un-used hud element.
remove_text_center(player, "pvp_revamped:shield_pool")
end
-- Save new player data to the table.
player_data[name] = victim_data
end
-- This needs to be the first punch function to prevent knockback on a immobilized player.
insert(minetest.registered_on_punchplayers, 1, punch)
minetest.callback_origins[punch] = {
mod = "pvp_revamped",
name = "register_on_punchplayer"
}