diff --git a/technic/tools/mining_lasers.lua b/technic/tools/mining_lasers.lua index 4c83ae9..d72d3a5 100644 --- a/technic/tools/mining_lasers.lua +++ b/technic/tools/mining_lasers.lua @@ -32,64 +32,54 @@ minetest.register_craft({ } }) --- Based on code by Uberi: https://gist.github.com/Uberi/3125280 +local scalar = vector.scalar or vector.dot or function vector.scalar(v1, v2) + return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z +end + +local function biggest_of_vec(vec) + if vec.x < vec.y then + if vec.y < vec.z then + return "z" + end + return "y" + end + if vec.x < vec.z then + return "z" + end + return "x" +end + local function rayIter(pos, dir, range) - local p = vector.round(pos) - local x_step, y_step, z_step = 0, 0, 0 - local x_component, y_component, z_component = 0, 0, 0 - local x_intersect, y_intersect, z_intersect = 0, 0, 0 - - if dir.x == 0 then - x_intersect = math.huge - elseif dir.x > 0 then - x_step = 1 - x_component = 1 / dir.x - x_intersect = x_component - else - x_step = -1 - x_component = 1 / -dir.x - end - if dir.y == 0 then - y_intersect = math.huge - elseif dir.y > 0 then - y_step = 1 - y_component = 1 / dir.y - y_intersect = y_component - else - y_step = -1 - y_component = 1 / -dir.y - end - if dir.z == 0 then - z_intersect = math.huge - elseif dir.z > 0 then - z_step = 1 - z_component = 1 / dir.z - z_intersect = z_component - else - z_step = -1 - z_component = 1 / -dir.z + -- make a table of possible movements + local step = {} + for i in pairs(pos) do + local v = math.sign(dir[i]) + if v ~= 0 then + step[i] = v + end end + local p return function() - if x_intersect < y_intersect then - if x_intersect < z_intersect then - p.x = p.x + x_step - x_intersect = x_intersect + x_component - else - p.z = p.z + z_step - z_intersect = z_intersect + z_component - end - elseif y_intersect < z_intersect then - p.y = p.y + y_step - y_intersect = y_intersect + y_component - else - p.z = p.z + z_step - z_intersect = z_intersect + z_component + if not p then + -- avoid skipping the first position + p = vector.round(pos) + return vector.new(p) end - if vector.distance(pos, p) > range then - return nil + + -- find the position which has the smallest distance to the line + local choose = {} + local choosefit = vector.new() + for i in pairs(step) do + choose[i] = vector.new(p) + choose[i][i] = choose[i][i] + step[i] + choosefit[i] = scalar(vector.normalize(vector.subtract(choose[i], pos)), dir) + end + p = choose[biggest_of_vec(choosefit)] + + if vector.distance(pos, p) <= range then + return vector.new(p) end - return p end end @@ -122,11 +112,11 @@ local function laser_shoot(player, range, particle_texture, sound) local start_pos = vector.new(player_pos) -- Adjust to head height - start_pos.y = start_pos.y + 1.9 + start_pos.y = start_pos.y + 1.625 minetest.add_particle({ - pos = startpos, - vel = dir, - acc = vector.multiply(dir, 50), + pos = start_pos, + velocity = dir, + acceleration = vector.multiply(dir, 50), expirationtime = range / 11, size = 1, texture = particle_texture .. "^[transform" .. math.random(0, 7),