-- LUALOCALS < ---------------------------------------------------------
local core, nc, vector
    = core, nc, vector
-- LUALOCALS > ---------------------------------------------------------

local function pumparticles(data, time, speed, qty)
	local pointed = data.pointed
	local nodedef = data.nodedef
	local pname = data.pname

	local stack = nc.stack_get(data.pos)
	if stack and not stack:is_empty() then
		nodedef = core.registered_items[stack:get_name()] or nodedef
	end

	local a = pointed.above
	local b = pointed.under
	local vel = vector.subtract(a, b)
	local mid = vector.multiply(vector.add(a, b), 0.5)
	local p1 = {x = vel.y, y = vel.z, z = vel.x}
	local p2 = {x = vel.z, y = vel.x, z = vel.y}
	local s1 = vector.add(vector.add(mid, vector.multiply(p1, 0.5)), vector.multiply(p2, 0.5))
	local s2 = vector.add(vector.add(mid, vector.multiply(p1, -0.5)), vector.multiply(p2, -0.5))
	vel = vector.multiply(vel, speed)

	return function()
		data.clearfx = nc.digparticles(nodedef, nc.underride(
				nc.underride({}, data.recipe
					and data.recipe.pumparticles or {}),
				{
					amount = qty,
					time = time,
					minpos = s1,
					maxpos = s2,
					minvel = vel,
					maxvel = vel,
					minexptime = 0.4,
					maxexptime = 0.9,
					minsize = 1,
					maxsize = 5,
					playername = pname
				})
		)
	end
end

local pummeling = {}

nc.register_on_dignode(function(_, _, digger)
		if not (digger and digger:is_player()) then return end
		pummeling[digger:get_player_name()] = nil
	end)

nc.register_on_punchnode(function(pos, node, puncher, pointed)
		if (not puncher:is_player()) or puncher:get_player_control().sneak then return end
		local pname = puncher:get_player_name()
		if not nc.interact(pname) then return end

		node = node or core.get_node(pos)
		local def = core.registered_items[node.name] or {}
		if not def.pointable then return end

		local wield = puncher:get_wielded_item()
		local now = core.get_us_time() / 1000000
		local pum = {
			action = "pummel",
			crafter = puncher,
			pname = pname,
			pos = pos,
			pointed = pointed,
			node = node,
			nodedef = def,
			start = now,
			wield = wield,
			wield_stripped = wield:get_name() .. " " .. wield:get_count(),
			count = 0,
		}
		pum.inprogress = pumparticles(pum, 1.5, 0.5, 8)

		local old = pummeling[pname]
		if old and old.clearfx then old.clearfx() end

		local hash = core.hash_node_position
		if old and hash(old.pos) == hash(pum.pos)
		and hash(old.pointed.above) == hash(pum.pointed.above)
		and hash(old.pointed.under) == hash(pum.pointed.under)
		and pum.wield_stripped == old.wield_stripped
		and old.last >= (now - 3)
		then pum = old end

		pum.count = pum.count + 1
		pum.last = now
		pum.duration = now - pum.start - 1
		pummeling[pname] = pum

		if pum.count < 2 then return end

		if nc.protection_test(pos, pname) then
			pummeling[pname] = nil
			return
		end

		local doneparticles = pumparticles(pum, 0.05, 1, 25)
		if nc.craft_check(pos, node, nc.underride({}, pum)) then
			doneparticles()
			pummeling[pname] = nil
			return
		end
	end)
