341 lines
8.9 KiB
Lua
341 lines
8.9 KiB
Lua
--[[
|
|
|
|
TechAge
|
|
=======
|
|
|
|
Copyright (C) 2019 Joachim Stolberg
|
|
|
|
AGPL v3
|
|
See LICENSE.txt for more information
|
|
|
|
Helper functions
|
|
|
|
]]--
|
|
|
|
-- for lazy programmers
|
|
local P = minetest.string_to_pos
|
|
local M = minetest.get_meta
|
|
|
|
-- Input data to generate the Param2ToDir table
|
|
local Input = {
|
|
8,9,10,11, -- 1
|
|
16,17,18,19, -- 2
|
|
4,5,6,7, -- 3
|
|
12,13,14,15, -- 4
|
|
0,1,2,3, -- 5
|
|
20,21,22,23, -- 6
|
|
}
|
|
|
|
-- allowed for digging
|
|
local RegisteredNodesToBeDug = {}
|
|
|
|
function techage.register_node_to_be_dug(name)
|
|
RegisteredNodesToBeDug[name] = true
|
|
end
|
|
|
|
-- translation from param2 to dir (out of the node upwards)
|
|
local Param2Dir = {}
|
|
for idx,val in ipairs(Input) do
|
|
Param2Dir[val] = math.floor((idx - 1) / 4) + 1
|
|
end
|
|
|
|
-- used by lamps and power switches
|
|
function techage.determine_node_bottom_as_dir(node)
|
|
return tubelib2.Turn180Deg[Param2Dir[node.param2] or 1]
|
|
end
|
|
|
|
function techage.determine_node_top_as_dir(node)
|
|
return Param2Dir[node.param2] or 1
|
|
end
|
|
|
|
-- rotation rules (screwdriver) for wallmounted "facedir" nodes
|
|
function techage.rotate_wallmounted(param2)
|
|
local offs = math.floor(param2 / 4) * 4
|
|
local rot = ((param2 % 4) + 1) % 4
|
|
return offs + rot
|
|
end
|
|
|
|
function techage.in_range(val, min, max)
|
|
val = tonumber(val)
|
|
if val < min then return min end
|
|
if val > max then return max end
|
|
return val
|
|
end
|
|
|
|
function techage.one_of(val, selection)
|
|
for _,v in ipairs(selection) do
|
|
if val == v then return val end
|
|
end
|
|
return selection[1]
|
|
end
|
|
|
|
function techage.index(list, x)
|
|
for idx, v in pairs(list) do
|
|
if v == x then return idx end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function techage.in_list(list, x)
|
|
for idx, v in pairs(list) do
|
|
if v == x then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function techage.add_to_set(set, x)
|
|
if not techage.index(set, x) then
|
|
table.insert(set, x)
|
|
end
|
|
end
|
|
|
|
function techage.get_node_lvm(pos)
|
|
local node = minetest.get_node_or_nil(pos)
|
|
if node then
|
|
return node
|
|
end
|
|
local vm = minetest.get_voxel_manip()
|
|
local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
|
|
local data = vm:get_data()
|
|
local param2_data = vm:get_param2_data()
|
|
local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
|
|
local idx = area:index(pos.x, pos.y, pos.z)
|
|
node = {
|
|
name = minetest.get_name_from_content_id(data[idx]),
|
|
param2 = param2_data[idx]
|
|
}
|
|
return node
|
|
end
|
|
|
|
--
|
|
-- Functions used to hide electric cable and biogas pipes
|
|
--
|
|
-- Overridden method of tubelib2!
|
|
function techage.get_primary_node_param2(pos, dir)
|
|
local npos = vector.add(pos, tubelib2.Dir6dToVector[dir or 0])
|
|
local param2 = M(npos):get_int("tl2_param2")
|
|
if param2 ~= 0 then
|
|
return param2, npos
|
|
end
|
|
end
|
|
|
|
-- Overridden method of tubelib2!
|
|
function techage.is_primary_node(pos, dir)
|
|
local npos = vector.add(pos, tubelib2.Dir6dToVector[dir or 0])
|
|
local param2 = M(npos):get_int("tl2_param2")
|
|
return param2 ~= 0
|
|
end
|
|
|
|
function techage.is_air_like(name)
|
|
local ndef = minetest.registered_nodes[name]
|
|
if ndef and ndef.buildable_to then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- returns true, if node can be dug, otherwise false
|
|
function techage.can_node_dig(node, ndef)
|
|
if RegisteredNodesToBeDug[node.name] then
|
|
return true
|
|
end
|
|
if not ndef then return false end
|
|
if node.name == "ignore" then return false end
|
|
if node.name == "air" then return true end
|
|
if ndef.buildable_to == true then return true end
|
|
if ndef.diggable == false then return false end
|
|
if ndef.after_dig_node then return false end
|
|
-- add it to the white list
|
|
RegisteredNodesToBeDug[node.name] = true
|
|
return true
|
|
end
|
|
|
|
techage.dig_states = {
|
|
NOT_DIGGABLE = 1,
|
|
INV_FULL = 2,
|
|
DUG = 3
|
|
}
|
|
|
|
-- Digs a node like a player would by utilizing a fake player object.
|
|
-- add_to_inv(itemstacks) is a method that should try to add the dropped stacks to an appropriate inventory.
|
|
-- The node will only be dug, if add_to_inv(itemstacks) returns true.
|
|
function techage.dig_like_player(pos, fake_player, add_to_inv)
|
|
local node = techage.get_node_lvm(pos)
|
|
local ndef = minetest.registered_nodes[node.name]
|
|
if not ndef or ndef.diggable == false or (ndef.can_dig and not ndef.can_dig(pos, fake_player)) then
|
|
return techage.dig_states.NOT_DIGGABLE
|
|
end
|
|
local drop_as_strings = minetest.get_node_drops(node)
|
|
local drop_as_stacks = {}
|
|
for _,itemstring in ipairs(drop_as_strings) do
|
|
drop_as_stacks[#drop_as_stacks+1] = ItemStack(itemstring)
|
|
end
|
|
local meta = M(pos)
|
|
if ndef.preserve_metadata then
|
|
ndef.preserve_metadata(pos, node, meta, drop_as_stacks)
|
|
end
|
|
|
|
if add_to_inv(drop_as_stacks) then
|
|
local oldmeta = meta:to_table()
|
|
minetest.remove_node(pos)
|
|
|
|
if ndef.after_dig_node then
|
|
ndef.after_dig_node(pos, node, oldmeta, fake_player)
|
|
end
|
|
return techage.dig_states.DUG
|
|
end
|
|
return techage.dig_states.INV_FULL
|
|
end
|
|
|
|
local function handle_drop(drop)
|
|
-- To keep it simple, return only the item with the lowest rarity
|
|
if drop.items then
|
|
local rarity = 9999
|
|
local name
|
|
for idx,item in ipairs(drop.items) do
|
|
if item.rarity and item.rarity < rarity then
|
|
rarity = item.rarity
|
|
name = item.items[1] -- take always the first item
|
|
else
|
|
return item.items[1] -- take always the first item
|
|
end
|
|
end
|
|
return name
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- returns the node name, if node can be dropped, otherwise nil
|
|
function techage.dropped_node(node, ndef)
|
|
if node.name == "air" then return end
|
|
--if ndef.buildable_to == true then return end
|
|
if not ndef.diggable then return end
|
|
if ndef.drop == "" then return end
|
|
if type(ndef.drop) == "table" then
|
|
return handle_drop(ndef.drop)
|
|
end
|
|
return ndef.drop or node.name
|
|
end
|
|
|
|
-- needed for windmill plants
|
|
local function determine_ocean_ids()
|
|
techage.OceanIdTbl = {}
|
|
for name, _ in pairs(minetest.registered_biomes) do
|
|
if string.find(name, "ocean") then
|
|
local id = minetest.get_biome_id(name)
|
|
--print(id, name)
|
|
techage.OceanIdTbl[id] = true
|
|
end
|
|
end
|
|
end
|
|
|
|
determine_ocean_ids()
|
|
|
|
-- check if natural water is on given position (water placed by player has param2 = 1)
|
|
function techage.is_ocean(pos)
|
|
if pos.y ~= 1 then return false end
|
|
local node = techage.get_node_lvm(pos)
|
|
if node.name ~= "default:water_source" then return false end
|
|
if node.param2 == 1 then return false end
|
|
return true
|
|
end
|
|
|
|
function techage.item_image(x, y, itemname)
|
|
local name, size = unpack(string.split(itemname, " "))
|
|
local label = ""
|
|
local tooltip = ""
|
|
local ndef = minetest.registered_nodes[name] or minetest.registered_items[name] or minetest.registered_craftitems[name]
|
|
|
|
if ndef and ndef.description then
|
|
local text = minetest.formspec_escape(ndef.description)
|
|
tooltip = "tooltip["..x..","..y..";1,1;"..text..";#0C3D32;#FFFFFF]"
|
|
end
|
|
|
|
if ndef and ndef.stack_max == 1 then
|
|
size = tonumber(size)
|
|
local offs = 0
|
|
if size < 10 then
|
|
offs = 0.65
|
|
elseif size < 100 then
|
|
offs = 0.5
|
|
elseif size < 1000 then
|
|
offs = 0.35
|
|
else
|
|
offs = 0.2
|
|
end
|
|
label = "label["..(x + offs)..","..(y + 0.45)..";"..tostring(size).."]"
|
|
end
|
|
|
|
return "box["..x..","..y..";0.85,0.9;#808080]"..
|
|
"item_image["..x..","..y..";1,1;"..itemname.."]"..
|
|
tooltip..
|
|
label
|
|
end
|
|
|
|
function techage.item_image_small(x, y, itemname, tooltip_prefix)
|
|
local name = unpack(string.split(itemname, " "))
|
|
local tooltip = ""
|
|
local ndef = minetest.registered_nodes[name] or minetest.registered_items[name] or minetest.registered_craftitems[name]
|
|
|
|
if ndef and ndef.description then
|
|
local text = minetest.formspec_escape(ndef.description)
|
|
tooltip = "tooltip["..x..","..y..";0.8,0.8;"..tooltip_prefix..": "..text..";#0C3D32;#FFFFFF]"
|
|
end
|
|
|
|
return "box["..x..","..y..";0.65,0.7;#808080]"..
|
|
"item_image["..x..","..y..";0.8,0.8;"..name.."]"..
|
|
tooltip
|
|
end
|
|
|
|
function techage.mydump(o, indent, nested, level)
|
|
local t = type(o)
|
|
if not level and t == "userdata" then
|
|
-- when userdata (e.g. player) is passed directly, print its metatable:
|
|
return "userdata metatable: " .. techage.mydump(getmetatable(o))
|
|
end
|
|
if t ~= "table" then
|
|
return basic_dump(o)
|
|
end
|
|
-- Contains table -> true/nil of currently nested tables
|
|
nested = nested or {}
|
|
if nested[o] then
|
|
return "<circular reference>"
|
|
end
|
|
nested[o] = true
|
|
indent = " "
|
|
level = level or 1
|
|
local t = {}
|
|
local dumped_indexes = {}
|
|
for i, v in ipairs(o) do
|
|
t[#t + 1] = techage.mydump(v, indent, nested, level + 1)
|
|
dumped_indexes[i] = true
|
|
end
|
|
for k, v in pairs(o) do
|
|
if not dumped_indexes[k] then
|
|
if type(k) ~= "string" or not is_valid_identifier(k) then
|
|
k = "["..techage.mydump(k, indent, nested, level + 1).."]"
|
|
end
|
|
v = techage.mydump(v, indent, nested, level + 1)
|
|
t[#t + 1] = k.." = "..v
|
|
end
|
|
end
|
|
nested[o] = nil
|
|
if indent ~= "" then
|
|
local indent_str = string.rep(indent, level)
|
|
local end_indent_str = string.rep(indent, level - 1)
|
|
return string.format("{%s%s%s}",
|
|
indent_str,
|
|
table.concat(t, ","..indent_str),
|
|
end_indent_str)
|
|
end
|
|
return "{"..table.concat(t, ", ").."}"
|
|
end
|
|
|
|
-- title bar help (width is the fornmspec width)
|
|
function techage.question_mark_help(width, tooltip)
|
|
local x = width- 0.6
|
|
return "label["..x..",-0.1;"..minetest.colorize("#000000", minetest.formspec_escape("[?]")).."]"..
|
|
"tooltip["..x..",-0.1;0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
|
|
end
|
|
|