dvornik/init.lua

208 lines
6.8 KiB
Lua
Executable File

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