VoxeLibre/mods/ENTITIES/mcl_minecarts/functions.lua

142 lines
3.3 KiB
Lua
Raw Normal View History

2021-05-25 00:43:42 +02:00
local vector = vector
2017-01-05 15:23:14 +01:00
function mcl_minecarts:get_sign(z)
if z == 0 then
return 0
else
return z / math.abs(z)
end
end
function mcl_minecarts:velocity_to_dir(v)
if math.abs(v.x) > math.abs(v.z) then
return vector.new(
mcl_minecarts:get_sign(v.x),
mcl_minecarts:get_sign(v.y),
0
)
2017-01-05 15:23:14 +01:00
else
return vector.new(
0,
mcl_minecarts:get_sign(v.y),
mcl_minecarts:get_sign(v.z)
)
2017-01-05 15:23:14 +01:00
end
end
function mcl_minecarts:is_rail(pos, railtype)
local node = minetest.get_node(pos).name
if node == "ignore" then
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(pos, pos)
local area = VoxelArea:new{
MinEdge = emin,
MaxEdge = emax,
}
local data = vm:get_data()
local vi = area:indexp(pos)
node = minetest.get_name_from_content_id(data[vi])
end
if minetest.get_item_group(node, "rail") == 0 then
return false
end
if not railtype then
return true
end
return minetest.get_item_group(node, "connect_to_raillike") == railtype
end
--[[
Returns a string description of a direction, with optional _up/_down suffix
]]
function mcl_minecarts:name_from_dir(dir, vertical)
local res = ""
if dir.z == 1 then res = res .. "n" end
if dir.z == -1 then res = res .. "s" end
if dir.x == -1 then res = res .. "w" end
if dir.x == 1 then res = res .. "e" end
if vertical then
if dir.y == 1 then res = res .. "_up" end
if dir.y == 1 then res = res .. "_down" end
2017-01-05 15:23:14 +01:00
end
return res
2017-01-05 15:23:14 +01:00
end
--[[
An array of (u,v,w) positions to check. Actual direction is u * dir + v * right + w * up
]]
local rail_checks = {
{ 1, 0, 0 }, -- forwards
{ 1, 0, 1 }, -- forwards and up
{ 1, 0, -1 }, -- forwards and down
{ 1, 1, 0 }, -- diagonal left
{ 0, 1, 0 }, -- left
{ 0, 1, 1 }, -- left and up
{ 0, 1, -1 }, -- left and down
{ 1, -1, 0 }, -- diagonal right
{ 0, -1, 0 }, -- right
{ 0, -1, 1 }, -- right and up
{ 0, -1, -1 }, -- right and down
{ -1, 0, 0 }, -- backwards
}
2024-03-11 21:14:11 +01:00
local rail_checks_diagonal = {
{ 1, 1, 0 }, -- forward along diagonal
{ 1, 0, 0 }, -- left
{ 0, 1, 0 }, -- right
}
local north = vector.new(0,0,1)
local south = vector.new(0,0,-1)
local east = vector.new(1,0,0)
local west = vector.new(-1,0,0)
-- Rotate diagonal directions 45 degrees clockwise
local diagonal_convert = {
2024-03-11 21:14:11 +01:00
nw = west,
ne = north,
se = east,
sw = south,
}
2017-01-05 15:23:14 +01:00
function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
local pos = vector.round(pos_)
2021-05-25 00:43:42 +02:00
-- Handle new track types that have track-specific direction handler
local node = minetest.get_node(pos)
local node_def = minetest.registered_nodes[node.name]
if node_def and node_def._mcl_minecarts and node_def._mcl_minecarts.get_next_dir then
return node_def._mcl_minecarts.get_next_dir(pos, dir, node)
end
-- Diagonal conversion
2024-03-11 21:14:11 +01:00
local checks = rail_checks
if dir.x ~= 0 and dir.z ~= 0 then
dir = diagonal_convert[ mcl_minecarts:name_from_dir(dir, false) ]
2024-03-11 21:14:11 +01:00
checks = rail_checks_diagonal
2017-01-05 15:23:14 +01:00
end
2021-05-25 00:43:42 +02:00
-- Calculate coordinate space
local right = vector.new( dir.z, dir.y, -dir.x)
local up = vector.new(0,1,0)
2021-05-25 00:43:42 +02:00
-- Perform checks
2024-03-11 21:14:11 +01:00
for _,check in ipairs(checks) do
local check_dir = dir * check[1] + right * check[2] + up * check[3]
local check_pos = pos + check_dir
if mcl_minecarts:is_rail(check_pos,railtype) then
return check_dir
2017-01-05 15:23:14 +01:00
end
end
2021-05-25 00:43:42 +02:00
return vector.new(0,0,0)
end