Files
modolith/mods/techage_modpack/techage/basis/fly_lib2.lua
T

274 lines
7.5 KiB
Lua

--[[
TechAge
=======
Copyright (C) 2020-2025 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Block fly/move library II
]]--
-- for lazy programmers
local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local S = techage.S
local fly1 = techage.flylib
local flylib2 = {}
local MAX_SPEED = 8
local DelayedJobs = {}
local function call_after(func, ...)
DelayedJobs[#DelayedJobs + 1] = {func = func, args = {...}}
end
local function run_delayed_jobs()
for idx = 1, #DelayedJobs do
local job = DelayedJobs[idx]
job.func(unpack(job.args))
end
DelayedJobs = {}
end
local function slots(slot)
return function(slot, i)
if slot == 0 then
i = i + 1
if i <= 16 then
return i, i -- variabel, result
end
else
i = i + 1
if i == 1 then
return slot,slot
end
end
end, tonumber(slot), 0 -- param, start value
end
local function destinations(nvm, dest_pos, slot)
if slot == 0 then
local tbl = {dest_pos}
-- Calculate dest-pos for all nodes
local base_pos = nvm.lNodes[1].base_pos
for idx = 2,16 do
if nvm.lNodes[idx] then
tbl[idx] = vector.add(vector.subtract(nvm.lNodes[idx].base_pos, base_pos), dest_pos)
end
end
return tbl
end
return {[slot] = dest_pos}
end
local function distance(v)
return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
end
local function remove_node(pos, node)
if minecart.is_cart(node.name) then
return minecart.remove_cart(pos)
else
local metadata = M(pos):to_table()
minetest.remove_node(pos)
return metadata
end
end
local function place_node(dest_pos, node, metadata)
local name = techage.get_node_lvm(dest_pos).name
local ndef = minetest.registered_nodes[name]
if minecart.is_cart(node.name) then
minecart.place_and_start_cart(dest_pos, {name = node.name, param2 = node.param2}, metadata)
return true
elseif ndef.buildable_to then
minetest.set_node(dest_pos, {name = node.name, param2 = node.param2})
local meta = M(dest_pos)
meta:from_table(metadata or {})
return true
end
end
local function get_node_from_inventory(inv, idx)
local stack = inv:get_stack("main", idx)
local param2 = stack:get_meta():get_int("param2")
inv:set_stack("main", idx, nil)
return {name = stack:get_name(), param2 = param2}
end
-- Move node from 'curr_pos' to 'dest_pos'
-- * pos is the controller block position
-- * max_speed is the maximum speed
-- * height is move block height as value between 0 and 1 and used to calculate the offset
-- for the attached object (player).
-- * yoffset is an additional offset for non-player objects
-- * idx is the node related movecontroller inventory slot (optional)
local function move_node(pos, curr_pos, dest_pos, max_speed, height, yoffset, idx)
local dir = fly1.determine_dir(curr_pos, dest_pos)
local obj, is_cart = fly1.node_to_entity(pos, curr_pos, dest_pos, idx)
if obj then
if is_cart then
fly1.attach_objects(curr_pos, 0, obj, yoffset, {x = 0, y = -0.4, z = 0})
else
local offs = {x=0, y=height or 1, z=0}
fly1.attach_objects(curr_pos, offs, obj, yoffset)
if dir.y == 0 then
if (dir.x ~= 0 and dir.z == 0) or (dir.x == 0 and dir.z ~= 0) then
fly1.attach_objects(curr_pos, dir, obj, yoffset)
end
end
end
local self = obj:get_luaentity()
self.path_idx = 2
self.lmove = {vector.subtract(dest_pos, curr_pos)}
self.max_speed = max_speed
self.yoffs = yoffset
self.idx = idx
fly1.move_entity(obj, dest_pos, dir)
return true
else
return false
end
end
-- Place node to start position, if necessary
local function correct_node(pos, idx, node, dest_pos)
local cnode = techage.get_node_lvm(node.curr_pos)
local inv = M(pos):get_inventory()
if inv:get_stack("main", idx):get_count() == 1 then
local ndef = minetest.registered_nodes[cnode.name]
if ndef.buildable_to then
local inode = get_node_from_inventory(inv, idx)
return place_node(node.curr_pos, inode)
else
local inode = get_node_from_inventory(inv, idx)
minetest.swap_node(node.curr_pos, inode)
call_after(minetest.set_node, node.curr_pos, {name = cnode.name, param2 = cnode.param2})
return true
end
end
if cnode.name == node.name then
return true
end
local dest_name = techage.get_node_lvm(dest_pos).name
if dest_name == node.name then
local metadata = remove_node(dest_pos, node)
return place_node(node.curr_pos, node, metadata)
end
return false
end
local function is_simple_node(node)
if not minecart.is_rail(pos, node.name) then
local ndef = minetest.registered_nodes[node.name]
return node.name ~= "air" and techage.can_dig_node(node.name, ndef) or minecart.is_cart(node.name)
end
end
function flylib2.get_pos(payload)
if payload then
local x,y,z = unpack(string.split(payload, ",", false, 2))
if z then
x = tonumber(x) or 0
y = tonumber(y) or 0
z = tonumber(z) or 0
return {x = x, y = y, z = z}
end
end
end
function flylib2.get_node_base_positions(lNodes)
local tbl = {}
for idx, item in ipairs(lNodes) do
tbl[idx] = item.base_pos
end
return tbl
end
function flylib2.get_nodes(pos_list)
local tbl = {}
for idx,pos in ipairs(pos_list) do
local node = techage.get_node_lvm(pos)
if is_simple_node(node) then
tbl[idx] = {base_pos = pos, curr_pos = pos, name = node.name, param2 = node.param2}
else
tbl[idx] = {base_pos = pos, curr_pos = pos, name = "techage:invalid_node", param2 = 0}
end
end
return tbl
end
function flylib2.valid_distance(nvm, destpos, slot, max_dist)
slot = slot > 0 and slot or 1
local basepos = nvm.lNodes[slot] and nvm.lNodes[slot].base_pos
if basepos and destpos then
local v = vector.subtract(destpos, basepos)
return distance(v) <= max_dist
end
return false
end
-- pos = movecontroller position
-- slot = inventory slot index (1..16) or 0 for all slots
function flylib2.reset_nodes(pos, nvm, slot)
local meta = M(pos)
if nvm.running then return false end
local max_speed = meta:contains("max_speed") and meta:get_float("max_speed") or MAX_SPEED
local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1) -- platform height
local yoffs = meta:get_float("offset") -- for non-player objects
for idx in slots(slot) do
nvm.lNodes = nvm.lNodes or {}
local node = nvm.lNodes[idx]
if node and node.curr_pos and node.curr_pos ~= node.base_pos then
if correct_node(pos, idx, node, node.base_pos) then
move_node(pos, node.curr_pos, node.base_pos, max_speed, height, yoffs, idx)
node.curr_pos = node.base_pos
end
end
end
run_delayed_jobs()
return true
end
-- pos = movecontroller position
-- slot = inventory slot index (1..16) or 0 for all slots
function flylib2.move_nodes(pos, nvm, dest_pos, slot)
local meta = M(pos)
if nvm.running then return false end
local max_speed = meta:contains("max_speed") and meta:get_float("max_speed") or MAX_SPEED
local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1) -- platform height
local yoffs = meta:get_float("offset") -- for non-player objects
local dests = destinations(nvm, dest_pos, slot)
for idx in slots(slot) do
local node = nvm.lNodes[idx]
local dest_pos = dests[idx]
if node and node.curr_pos and node.curr_pos ~= dest_pos then
if correct_node(pos, idx, node, dest_pos) then
move_node(pos, node.curr_pos, dest_pos, max_speed, height, yoffs, idx)
node.curr_pos = dest_pos
end
end
end
run_delayed_jobs()
return true
end
minetest.register_craftitem("techage:invalid_node", {
description = S("Invalid node"),
inventory_image = "techage_invalid_node.png",
groups = {not_in_creative_inventory = 1},
})
techage.flylib2 = flylib2