local MODNAME = "dvornik" local VENIK_ACTIVE_TIME = 0.55 local DEBUG = true local active_veniks = {} local function is_venik_active(player) return active_veniks[player] end local function deactivate_venik(player) active_veniks[player] = nil end local function activate_venik(player, venik) -- FIXME venik is not used if is_venik_active(player) then return end minetest.sound_play('dvornik_sweep', { pos = player:get_pos(), max_hear_distance = 10 }) active_veniks[player] = minetest.after(VENIK_ACTIVE_TIME, deactivate_venik, player) end minetest.register_tool( "dvornik:venik", { description = "A venik for a dvornik", inventory_image = "dvornik_venik.png", --wield_scale = {x = 1, y = -1, z = 1}, on_use = function(itemstack, user, pointed_thing) if not (user and user:is_player()) then return itemstack end -- TODO change it's visuals while active? activate_venik(user, itemstack) -- TODO short cooldown? return itemstack end, tool_capabilities = { full_punch_inverval = VENIK_ACTIVE_TIME * 10 } } ) if DEBUG then minetest.register_tool( "dvornik:garbage", { description = "A garbage for a dvornik to clean up", inventory_image = "garbage.png", on_use = function(itemstack, user, pointed_thing) local garbage_list = { "dirt", "cobble", "wood", "stick", "coal_lump", "gold_lump", "apple", "sand", "steel_ingot", "copper_ingot" } if not (user and user:is_player()) then return itemstack end local pos = user:get_pos() for i = 1, 3 do for _, item in pairs(garbage_list) do local r = 4.0 local p = vector.add(pos, vector.new((math.random() - 0.5) * r, 0.5, (math.random() - 0.5) * r)) minetest.add_item(p, "default:" .. item) end end return itemstack end } ) end local function player_get_eye_pos(player) local p_pos = player:get_pos() local p_eye_height = player:get_properties().eye_height p_pos.y = p_pos.y + p_eye_height local p_eye_pos = p_pos local p_eye_offset = vector.multiply(player:get_eye_offset(), 0.1) local yaw = player:get_look_horizontal() p_eye_pos = vector.add(p_eye_pos, vector.rotate_around_axis(p_eye_offset, { x = 0, y = 1, z = 0 }, yaw)) return p_eye_pos end local function add_debug_particle(pos) minetest.add_particle({ pos = pos, expirationtime = 2, size = 1, texture = "test.png" }) end -- TODO recheck if player leaving the server is not crashing it local function try_to_pickup(player, pointed_thing) -- TODO check if we can pick up more item -- TODO if can't pick up any more items, then maybe move the item entity a bit? local item = pointed_thing.ref:get_luaentity() if item and item.on_punch then -- TODO probaly don't need this check minetest.sound_play("dvornik_pickup", { to_player = player:get_player_name() --pos = player:get_pos(), --max_hear_distance = 10 }) minetest.add_particle({ pos = pointed_thing.ref:get_pos(), expirationtime = 1, size = 1, texture = "tnt_smoke.png" -- TODO }) item:on_punch(player) end end local RANGE = 3.0 --local RADIUS = 1.0 local function trace_and_pickup(player) local p_eye_pos = player_get_eye_pos(player) local prev_point = active_veniks[player] local to = vector.add(p_eye_pos, vector.multiply(player:get_look_dir(), RANGE)) local ray = minetest.raycast( p_eye_pos, to, true, -- point to objects false) -- point to liquids -- First trace: find what player is looking at local pointed_thing = ray:next() local current_point = nil while pointed_thing do if DEBUG and pointed_thing.type ~= "nothing" and not (pointed_thing.type == "object" and pointed_thing.ref == player) then local point = pointed_thing.intersection_point add_debug_particle(point) end if pointed_thing.type == "object" then if pointed_thing.ref ~= player then -- exclude the player themselves from the raycast -- "pickup" -- for _, obj in pairs(minetest.get_objects_inside_radius(point, RADIUS)) do -- obj:remove() -- end -- Player is looking at an item: use the item position current_point = pointed_thing.ref:get_pos() break end elseif pointed_thing.type == "node" then -- move intersection point a little bit away from the block local HEIGHT = 0.2 -- Player is looking at a block: move a little bit away from it current_point = vector.multiply( vector.add(pointed_thing.intersection_point, pointed_thing.intersection_normal), HEIGHT) break end pointed_thing = ray:next() end -- Second trace: trace from old previous position to current if not prev_point then prev_point = p_eye_pos end -- TODO maybe limit the distance between prev/current points? if prev_point and prev_point.x and current_point and current_point.x then local ray = minetest.raycast(prev_point, current_point, true, false) local pointed_thing = ray:next() while pointed_thing do if pointed_thing.type == "object" then if pointed_thing.ref ~= player then -- Just pick up everything that was between -- previous and current points try_to_pickup(player, pointed_thing) end end pointed_thing = ray:next() end end -- store the point for next timestep active_veniks[player] = current_point end minetest.register_globalstep(function(_dtime) for player, _ in pairs(active_veniks) do trace_and_pickup(player) end end ) minetest.register_on_leaveplayer(function(player, timed_out) deactivate_venik(player) end) -- minetest.register_on_item_pickup(function(itemstack, picker, pointed_thing, time_from_last_punch, ...) -- end) -- minetest.item_pickup(itemstack, picker, pointed_thing, time_from_last_punch, ...) -- on_pickup