mods that hopefully work for a TechAge-based pack

This commit is contained in:
tangent committed 2026-09-09 06:27:51 -06:00
1 parent 4e6b08d194
commit c27db2a537
6234 files changed
+375578

No files matched your search

@@ -0,0 +1,108 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Door block
]]--
local M = minetest.get_meta
local S = techage.S
-- See also gateblock!!!
local NUM_TEXTURES = 22
local sTextures = "Wood,Aspen Wood,Jungle Wood,Pine Wood,"..
"Cobblestone,Sandstone,Stone,Desert Sandstone,"..
"Desert Stone,Silver Sandstone,Mossy Cobble,Desert Cobble,"..
"Copper,Steel,Tin,Coral,"..
"Glas,Obsidian Glas,Basalt Glass,Basalt Glass 2,"..
"Ice,Gate Wood"
local tTextures = {
["Wood"]=1, ["Aspen Wood"]=2, ["Jungle Wood"]=3, ["Pine Wood"]=4,
["Cobblestone"]=5, ["Sandstone"]=6, ["Stone"]=7, ["Desert Sandstone"]=8,
["Desert Stone"]=9, ["Silver Sandstone"]=10, ["Mossy Cobble"]=11, ["Desert Cobble"]=12,
["Copper"]=13, ["Steel"]=14, ["Tin"]=15, ["Coral"]=16,
["Glas"]=17, ["Obsidian Glas"]=18, ["Basalt Glass"]=19, ["Basalt Glass 2"]=20,
["Ice"]=21, ["Gate Wood"]=22,
}
local tPgns = {"default_wood.png", "default_aspen_wood.png", "default_junglewood.png", "default_pine_wood.png",
"default_cobble.png", "default_sandstone.png", "default_stone.png", "default_desert_sandstone.png",
"default_desert_stone_block.png", "default_silver_sandstone.png", "default_mossycobble.png", "default_desert_cobble.png",
"default_copper_block.png", "default_steel_block.png", "default_tin_block.png", "default_coral_skeleton.png",
"default_glass.png", "default_obsidian_glass.png", "techage_basalt_glass.png", "techage_basalt_glass2.png",
"default_ice.png", "techage_gate.png"}
for idx,pgn in ipairs(tPgns) do
minetest.register_node("techage:doorblock"..idx, {
description = S("TechAge Door Block"),
tiles = {
pgn.."^[transformR90",
pgn,
pgn.."^[transformR90",
pgn.."^[transformR90",
pgn,
pgn.."^[transformFX",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, -1/16, 8/16, 8/16, 1/16},
},
},
after_place_node = function(pos, placer)
M(pos):set_string("formspec", "size[3,2]"..
"label[0,0;Select texture]"..
"dropdown[0,0.5;3;type;"..sTextures..";"..NUM_TEXTURES.."]"..
"button_exit[0.5,1.5;2,1;exit;Save]")
end,
on_receive_fields = function(pos, formname, fields, player)
local meta = minetest.get_meta(pos)
local node = minetest.get_node(pos)
if fields.type then
node.name = "techage:doorblock"..tTextures[fields.type]
minetest.swap_node(pos, node)
end
if fields.exit then
meta:set_string("formspec", "")
local number = techage.add_node(pos, node.name)
meta:set_string("infotext", S("TechAge Door Block").." "..number)
end
end,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
end,
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = techage.BLEND,
sunlight_propagates = true,
sounds = default.node_sound_stone_defaults(),
groups = {cracky=2, choppy=2, crumbly=2, techage_door = 1,
not_in_creative_inventory = idx==NUM_TEXTURES and 0 or 1},
is_ground_content = false,
drop = "techage:doorblock"..NUM_TEXTURES,
},
techage.register_node({"techage:doorblock"..idx}, {}))
end
minetest.register_craft({
output = "techage:doorblock"..NUM_TEXTURES,
recipe = {
{"techage:basalt_glass_thin", "", ""},
{"default:mese_crystal_fragment", "",""},
{"group:wood", "", ""},
},
})
@@ -0,0 +1,147 @@
--[[
TechAge
=======
Copyright (C) 2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Door/Gate Controller
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local logic = techage.logic
local function formspec(meta)
local numbers = meta:get_string("numbers") or ""
return "size[7.5,3]"..
"field[0.5,1;7,1;numbers;"..S("Insert door/gate block number(s)")..";"..numbers.."]" ..
"button_exit[2,2;3,1;exit;"..S("Save").."]"
end
local function store_door_data(pos)
local nvm = techage.get_nvm(pos)
nvm.door_state = false
local numbers = M(pos):get_string("numbers")
nvm.door_blocks = {}
for _,num in ipairs(string.split(numbers, " ")) do
local info = techage.get_node_info(num)
if info and info.pos then
local node = techage.get_node_lvm(info.pos)
table.insert(nvm.door_blocks, {pos = info.pos, name = node.name, param2 = node.param2})
end
end
end
local function swap_door_nodes(pos, open)
local nvm = techage.get_nvm(pos)
if nvm.door_state ~= open then
nvm.door_state = open
for _,item in ipairs(nvm.door_blocks or {}) do
if item.pos and item.name and item.param2 then
local node = techage.get_node_lvm(item.pos)
if open then
if node.name == item.name then
minetest.remove_node(item.pos)
item.removed = true
else
item.removed = false
end
elseif techage.is_air_like(node.name) and item.removed then
minetest.add_node(item.pos, {name = item.name, param2 = item.param2})
end
end
end
end
end
minetest.register_node("techage:ta3_doorcontroller", {
description = S("TA3 Door Controller"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3_top.png",
"techage_filling_ta3.png^techage_frame_ta3_top.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_doorcontroller.png",
},
after_place_node = function(pos, placer)
local meta = M(pos)
local mem = techage.get_mem(pos)
logic.after_place_node(pos, placer, "techage:ta3_doorcontroller", S("TA3 Door Controller"))
logic.infotext(meta, S("TA3 Door Controller"))
meta:set_string("formspec", formspec(meta))
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
if techage.check_numbers(fields.numbers, player:get_player_name()) then
swap_door_nodes(pos, false)
meta:set_string("numbers", fields.numbers)
logic.infotext(M(pos), S("TA3 Door Controller"))
meta:set_string("formspec", formspec(meta))
store_door_data(pos)
end
end,
techage_set_numbers = function(pos, numbers, player_name)
local meta = M(pos)
local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Door Controller"))
if res then
swap_door_nodes(pos, false)
meta:set_string("formspec", formspec(meta))
store_door_data(pos)
end
return res
end,
after_dig_node = function(pos, oldnode, oldmetadata)
swap_door_nodes(pos, false)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:ta3_doorcontroller"}, {
on_recv_message = function(pos, src, topic, payload)
if topic == "on" then
swap_door_nodes(pos, true)
elseif topic == "off" then
swap_door_nodes(pos, false)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 1 and payload[1] == 1 then
swap_door_nodes(pos, true)
return 0
elseif topic == 1 and payload[1] == 0 then
swap_door_nodes(pos, false)
return 0
else
return 2
end
end,
})
minetest.register_craft({
output = "techage:ta3_doorcontroller",
recipe = {
{"", "group:wood",""},
{"techage:vacuum_tube", "", "default:mese_crystal_fragment"},
{"", "group:wood", ""},
},
})
@@ -0,0 +1,477 @@
--[[
TechAge
=======
Copyright (C) 2020-2025 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Door/Gate Controller 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 S = techage.S
local MP = minetest.get_modpath("techage")
local mark = dofile(MP .. "/basis/mark_lib.lua")
local logic = techage.logic
local fly = techage.flylib
local NUMSLOTS = 16
--------------------------------------------------------------------------
-- helper functions
--------------------------------------------------------------------------
local function get_positions(nvm)
local lpos = {}
for idx,cfg in ipairs(nvm.config or {}) do
lpos[idx] = cfg.pos
end
return lpos
end
-- Slot state: 1 = Initial state (reset), 2 = Exchange state
local function get_state(nvm, number)
if nvm.config[number] then
return nvm.config[number].state and 1 or 2
end
return 0
end
local function is_simple_node(pos, name)
if not minecart.is_rail(pos, name) then
local ndef = minetest.registered_nodes[name]
return techage.can_dig_node(name, ndef) or minecart.is_cart(name) or
doors.registered_doors[name] or doors.registered_trapdoors[name]
end
return false
end
-- Slot Configuration {
-- pos, -- pos from the node in the inventory
-- param2, -- param2 from the node in the inventory
-- state, -- false = block is dug/slot is filled (set), true = block is set/slot is empty (reset)
-- nameS, -- name of the node in the world, if state = false (set)
-- nameR, -- name of the node in the worls, if state = true (reset)
-- }
local function gen_config(pos, pos_list)
local nvm = techage.get_nvm(pos)
nvm.config = {}
for idx,pos in ipairs(pos_list) do
local node = techage.get_node_lvm(pos)
nvm.config[idx] = {pos = pos, param2 = node.param2, state = true, nameR = node.name, nameS = "air"}
end
end
local function gen_config_initial(pos)
local inv = M(pos):get_inventory()
local item_list = inv:get_list("main")
local nvm = techage.get_nvm(pos)
nvm.config = {}
nvm.pos_list = nvm.pos_list or {}
nvm.param2_list = nvm.param2_list or {}
local len = #nvm.pos_list
for idx = 1, len do
-- The status is not yet known. It is assumed that the block is set (status = true)
-- if the inventory is empty.
local item = item_list[idx]
local node = techage.get_node_lvm(nvm.pos_list[idx])
local state = (item and item:get_count() > 0) == false
if state then
nvm.config[idx] = {pos = nvm.pos_list[idx], param2 = nvm.param2_list[idx], state = state, nameR = node.name, nameS = "air"}
else
nvm.config[idx] = {pos = nvm.pos_list[idx], param2 = nvm.param2_list[idx], state = state, nameR = "air", nameS = node.name}
end
end
nvm.pos_list = nil
nvm.param2_list = nil
end
local function add_node_names(pos, nvm)
local inv = M(pos):get_inventory()
local item_list = inv:get_list("main")
for idx = 1, #nvm.config do
local node = techage.get_node_lvm(nvm.config[idx].pos)
local item = item_list[idx]
if nvm.config[idx].state then
nvm.config[idx].nameR = node.name
nvm.config[idx].nameS = item:get_count() > 0 and item:get_name() or "air"
else
nvm.config[idx].nameR = item:get_count() > 0 and item:get_name() or "air"
nvm.config[idx].nameS = node.name
end
end
end
--------------------------------------------------------------------------
-- formspec
--------------------------------------------------------------------------
local function formspec1(nvm, meta)
local status = meta:get_string("status")
local play_sound = dump(nvm.play_sound or false)
return "size[8,7]"..
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";1;;true]"..
"button_exit[0.7,0.0;3,1;record;"..S("Record").."]"..
"button[4.3,0.0;3,1;ready;"..S("Done").."]"..
"button_exit[0.7,0.9;3,1;reset;"..S("Reset").."]"..
"button_exit[4.3,0.9;3,1;exchange;"..S("Exchange").."]"..
"button_exit[0.7,1.8;3,1;show;"..S("Show positions").."]"..
"checkbox[4.3,1.8;play_sound;"..S("with door sound")..";"..play_sound.."]"..
"label[0.5,2.8;"..status.."]"..
"list[current_player;main;0,3.3;8,4;]"
end
local function formspec2(nvm)
local lbls = {}
for idx,item in ipairs(nvm.config or {}) do
local x = ((idx-1) % 8) + 0.3
local y = math.floor((idx-1) / 8) * 2.4
if item.state then
lbls[idx] = "label[" .. x .."," .. y .. ";" .. idx .. "]"
else
lbls[idx] = "label[" .. x .."," .. y .. ";" .. idx .. " *]"
end
end
return "size[8,7]"..
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";2;;true]"..
table.concat(lbls, "")..
"list[context;main;0,0.5;8,2;]"..
"list[current_player;main;0,3.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
--------------------------------------------------------------------------
-- Exchange nodes
--------------------------------------------------------------------------
local function remove_hidden_door_node(pos)
local above = vector.offset(pos, 0, 1, 0)
if minetest.get_node(above).name == "doors:hidden" then
minetest.remove_node(above)
end
end
local function exchange_node(cfg, item)
local node = techage.get_node_lvm(cfg.pos)
if is_simple_node(cfg.pos, node.name) then
local name = item:get_count() > 0 and item:get_name() or "air"
local expected_node_name = cfg.state and cfg.nameR or cfg.nameS
if fly.exchange_node(cfg.pos, name, cfg.param2, expected_node_name) then
remove_hidden_door_node(cfg.pos)
cfg.param2 = node.param2
cfg.state = not cfg.state
if node.name ~= "air" then
return ItemStack(node.name)
else
return ItemStack()
end
end
end
return item
end
local function exchange_nodes(pos, nvm, slot, force)
local inv = M(pos):get_inventory()
local item_list = inv:get_list("main")
if item_list == nil then
return false
end
local res = false
nvm.config = nvm.config or {}
local len = #nvm.config
for idx = (slot or 1), (slot or len) do
local cfg = nvm.config[idx]
local state = cfg.state
local item = item_list[idx]
if (force == nil)
or (force == "exch")
or (force == "dig" and item:get_count() == 0)
or (force == "set" and item:get_count() > 0)
or (force == "to2" and state)
or (force == "to1" and not state) then
item_list[idx] = exchange_node(cfg, item)
nvm.config[idx].state = not state
res = true
end
end
inv:set_list("main", item_list)
return res
end
local function reset_config(pos, nvm)
local inv = M(pos):get_inventory()
local item_list = inv:get_list("main")
for idx, cfg in ipairs(nvm.config or {}) do
local item = item_list[idx]
if not cfg.state then
item_list[idx] = exchange_node(cfg, item)
end
end
inv:set_list("main", item_list)
end
local function exchange_with_sound(pos)
local nvm = techage.get_nvm(pos)
if nvm.play_sound then
minetest.sound_play("doors_door_open", {
pos = pos,
gain = 1,
max_hear_distance = 15})
end
return exchange_nodes(pos, nvm)
end
local function exchange_with_learning(pos)
local nvm = techage.get_nvm(pos)
add_node_names(pos, nvm)
return exchange_with_sound(pos)
end
minetest.register_node("techage:ta3_doorcontroller2", {
description = S("TA3 Door Controller II"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3_top.png",
"techage_filling_ta3.png^techage_frame_ta3_top.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_doorcontroller.png",
},
after_place_node = function(pos, placer, itemstack)
local meta = M(pos)
local inv = meta:get_inventory()
inv:set_size('main', NUMSLOTS)
logic.after_place_node(pos, placer, "techage:ta3_doorcontroller2", S("TA3 Door Controller II"))
logic.infotext(meta, S("TA3 Door Controller II"))
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec1(nvm, meta))
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
nvm.fs2_active = false
if fields.tab == "2" then
meta:set_string("formspec", formspec2(nvm))
nvm.fs2_active = true
return
elseif fields.tab == "1" then
meta:set_string("formspec", formspec1(nvm, meta))
nvm.fs2_active = true
return
elseif fields.record then
nvm.recording = true
meta:set_string("status", S("Recording..."))
local name = player:get_player_name()
minetest.chat_send_player(name, S("Click on all the blocks that are part of the door/gate"))
mark.unmark_all(name)
mark.start(name, NUMSLOTS)
meta:set_string("stored_config", "")
meta:set_string("formspec", formspec1(nvm, meta))
elseif fields.ready and nvm.recording then
nvm.recording = false
local name = player:get_player_name()
local pos_list = mark.get_poslist(name)
gen_config(pos, pos_list)
local text = #pos_list.." "..S("block positions are stored.")
meta:set_string("status", text)
mark.unmark_all(name)
mark.stop(name)
meta:set_string("stored_config", "")
meta:set_string("formspec", formspec1(nvm, meta))
elseif fields.exchange then
if exchange_with_learning(pos) then
meta:set_string("status", S("Blocks exchanged"))
meta:set_string("formspec", formspec1(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
end
elseif fields.show then
local name = player:get_player_name()
local lpos = get_positions(nvm)
mark.mark_positions(name, lpos, 300)
elseif fields.reset then
reset_config(pos, nvm)
meta:set_string("status", S("Blocks reset"))
meta:set_string("formspec", formspec1(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
elseif fields.play_sound then
nvm.play_sound = fields.play_sound == "true"
meta:set_string("formspec", formspec1(nvm, meta))
end
end,
allow_metadata_inventory_move = function()
return 0
end,
allow_metadata_inventory_take = function()
return 0
end,
allow_metadata_inventory_put = function()
return 0
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if not clicker or minetest.is_protected(pos, clicker:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if nvm.fs2_active then
meta:set_string("formspec", formspec2(nvm))
else
meta:set_string("formspec", formspec1(nvm, meta))
end
end,
can_dig = function(pos, player)
if player and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = minetest.get_inventory({type="node", pos=pos})
return inv:is_empty("main")
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name()
mark.unmark_all(name)
techage.remove_node(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:ta3_doorcontroller2"}, {
on_recv_message = function(pos, src, topic, payload)
if topic == "on" then
return exchange_with_sound(pos)
elseif topic == "off" then
return exchange_with_sound(pos)
elseif topic == "exchange" then
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, tonumber(payload), "exch")
elseif topic == "to1" then
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, tonumber(payload), "to1")
elseif topic == "to2" then
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, tonumber(payload), "to2")
elseif topic == "set" then
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, tonumber(payload), "set")
elseif topic == "dig" then
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, tonumber(payload), "dig")
elseif topic == "get" then
local nvm = techage.get_nvm(pos)
return get_state(nvm, tonumber(payload))
elseif topic == "reset" then
local nvm = techage.get_nvm(pos)
return reset_config(pos, nvm)
end
return false
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 1 and payload[1] == 1 then
return exchange_with_sound(pos) and 0 or 3
elseif topic == 1 and payload[1] == 0 then
return exchange_with_sound(pos) and 0 or 3
elseif topic == 9 and payload[1] == 0 then -- Exchange Block
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, payload[2] or 1, "exch") and 0 or 3
elseif topic == 9 and payload[1] == 1 then -- Set Block
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, payload[2] or 1, "set") and 0 or 3
elseif topic == 9 and payload[1] == 2 then -- Dig Block
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, payload[2] or 1, "dig") and 0 or 3
elseif topic == 9 and payload[1] == 3 then -- reset
local nvm = techage.get_nvm(pos)
return reset_config(pos, nvm) and 0 or 3
elseif topic == 9 and payload[1] == 4 then -- to1
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, payload[2] or 1, "to1") and 0 or 3
elseif topic == 9 and payload[1] == 5 then -- to2
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, payload[2] or 1, "to2") and 0 or 3
end
return 2
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 147 then -- Get State
local nvm = techage.get_nvm(pos)
return 0, {get_state(nvm, tonumber(payload[1]))}
end
return 2, {0}
end,
on_node_load = function(pos)
local nvm = techage.get_nvm(pos)
if nvm.config == nil then
gen_config_initial(pos)
elseif nvm.config[1] and nvm.config[1].nameS == nil then
add_node_names(pos, nvm)
end
end,
})
minetest.register_alias("techage:ta3_doorcontroller3", "techage:ta3_doorcontroller2")
minetest.register_craft({
type = "shapeless",
output = "techage:ta3_doorcontroller2",
recipe = {"techage:ta3_doorcontroller"},
})
local Doors = {
"doors:door_steel",
"doors:prison_door",
"doors:rusty_prison_door",
"doors:trapdoor_steel",
"doors:door_glass",
"doors:door_wood",
"doors:door_obsidian_glass",
"doors:japanese_door",
"doors:screen_door",
"doors:slide_door",
"doors:trapdoor",
"doors:woodglass_door",
"xpanes:door_steel_bar",
"xpanes:trapdoor_steel_bar",
}
for _, name in ipairs(Doors) do
for _, postfix in ipairs({"a", "b", "c", "d"}) do
techage.register_simple_nodes({name .. "_" .. postfix}, true)
fly.protect_door_from_being_opened(name .. "_" .. postfix)
end
end
local ProtectorDoors = {
"protector:door_steel",
"protector:door_wood",
"protector:trapdoor",
"protector:trapdoor_steel",
}
for _, name in ipairs(ProtectorDoors) do
for _, postfix in ipairs({"b_1", "b_2", "t_1", "t_2"}) do
techage.register_simple_nodes({name .. "_" .. postfix}, true)
fly.protect_door_from_being_opened(name .. "_" .. postfix)
end
end
@@ -0,0 +1,306 @@
--[[
TechAge
=======
Copyright (C) 2020-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA5 Fly Controller
]]--
-- 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 MP = minetest.get_modpath("techage")
local mark = dofile(MP .. "/basis/mark_lib.lua")
local fly = techage.flylib
local MAX_DIST = 1500
local MAX_BLOCKS = 32
local EX_POINTS = 40
local WRENCH_MENU = {
{
type = "dropdown",
choices = "0.5,1,2,4,6,8",
name = "max_speed",
label = S("Maximum Speed"),
tooltip = S("Maximum speed for moving blocks"),
default = "8",
},
{
type = "float",
name = "height",
label = S("Move block height"),
tooltip = S("Value in the range of 0.0 to 1.0"),
default = "1.0",
},
{
type = "float",
name = "offset",
label = S("Object offset"),
tooltip = S("Y-offset for non-player objects like vehicles (-0.5 to 0.5)"),
default = "0.0",
},
{
type = "dropdown",
choices = "disable,enable",
name = "teleport_mode",
label = S("Teleport mode"),
tooltip = S("Move a player without moving blocks"),
default = "disable",
},
{
type = "dropdown",
choices = "A-B / B-A,move xyz",
name = "opmode",
label = S("Operational mode"),
tooltip = S("Switch to the remote controlled 'move xyz' mode"),
default = "A-B / B-A",
},
}
local function formspec(nvm, meta)
local status = meta:get_string("status")
local path = minetest.formspec_escape(meta:contains("fs_path") and meta:get_string("fs_path") or
meta:contains("path") and meta:get_string("path") or "0,3,0")
return "size[8,6.7]" ..
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=true]" ..
"box[0,-0.1;7.2,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA5 Fly Controller")) .. "]" ..
techage.wrench_image(7.4, -0.05) ..
"button[0.1,0.7;3.8,1;record;" .. S("Record") .. "]" ..
"button[4.1,0.7;3.8,1;done;" .. S("Done") .. "]" ..
"textarea[0.4,2.1;3.8,4.4;path;" .. S("Flight route (A to B)") .. ";"..path.."]" ..
"button[4.1,1.8;3.8,1;store;" .. S("Store") .. "]" ..
"button[4.1,2.6;3.8,1;test;" .. S("Test") .. "]" ..
"button[4.1,3.4;3.8,1;moveAB;" .. S("Move A-B") .. "]" ..
"button[4.1,4.2;3.8,1;moveBA;" .. S("Move B-A") .. "]" ..
"button[4.1,5.0;3.8,1;move;" .. S("Move") .. "]" ..
"label[0.3,6.3;" .. status .. "]"
end
minetest.register_node("techage:ta5_flycontroller", {
description = S("TA5 Fly Controller"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta5_top.png",
"techage_filling_ta4.png^techage_frame_ta5_top.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_movecontroller.png",
},
after_place_node = function(pos, placer, itemstack)
local meta = M(pos)
techage.logic.after_place_node(pos, placer, "techage:ta5_flycontroller", S("TA5 Fly Controller"))
techage.logic.infotext(meta, S("TA5 Fly Controller"))
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec(nvm, meta))
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
if techage.get_expoints(player) < EX_POINTS then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if fields.record then
nvm.lpos1 = {}
nvm.lpos2 = {}
nvm.moveBA = false
nvm.running = nil
meta:set_string("status", S("Recording..."))
local name = player:get_player_name()
minetest.chat_send_player(name, S("Click on all blocks that shall be moved"))
mark.start(name, MAX_BLOCKS)
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.done then
local name = player:get_player_name()
local pos_list = mark.get_poslist(name)
local _, err = fly.to_path(fields.path, MAX_DIST)
if not err then
meta:set_string("fs_path", fields.path)
meta:set_string("path", fields.path)
end
nvm.running = nil
local text = #pos_list.." "..S("block positions are stored.")
meta:set_string("status", text)
nvm.lpos1 = pos_list
mark.unmark_all(name)
mark.stop(name)
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.store then
local _, err = fly.to_path(fields.path, MAX_DIST)
if not err then
meta:set_string("path", fields.path)
meta:set_string("fs_path", fields.path)
meta:set_string("status", S("Stored"))
else
meta:set_string("path", "0,0,0")
meta:set_string("fs_path", fields.path)
meta:set_string("status", err)
end
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
nvm.moveBA = false
nvm.running = nil
elseif fields.test then
local path, err = fly.to_path(fields.path, MAX_DIST)
if err then
meta:set_string("status", err)
elseif path and nvm.lpos1 and nvm.lpos1[1] then
local pos = table.copy(nvm.lpos1[1])
if pos then
for _, offs in ipairs(path) do
local pos2 = vector.add(pos, offs)
local s = string.format("[TA4 Fly Controller] %s + %s = %s", P2S(pos), P2S(offs), P2S(pos2))
minetest.chat_send_player(player:get_player_name(), s)
pos = pos2
end
meta:set_string("status", S("See chat output"))
else
minetest.chat_send_player(player:get_player_name(), S("[TA4 Fly Controller] Recording is missing!"))
meta:set_string("status", S("Error: Recording is missing !!"))
end
else
if nvm.lpos1 then
minetest.chat_send_player(player:get_player_name(), S("[TA4 Fly Controller] Invalid path!"))
meta:set_string("status", S("Error: Invalid path !!"))
else
minetest.chat_send_player(player:get_player_name(), S("[TA4 Fly Controller] Recording is missing!"))
meta:set_string("status", S("Error: Recording is missing !!"))
end
end
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.moveAB then
meta:set_string("status", "")
if fly.move_to_other_pos(pos, false) then
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
end
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.moveBA then
meta:set_string("status", "")
if fly.move_to_other_pos(pos, true) then
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
end
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.move then
meta:set_string("status", "")
if fly.move_to_other_pos(pos, nvm.moveBA) then
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
end
meta:set_string("formspec", formspec(nvm, meta))
end
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name()
mark.unmark_all(name)
mark.stop(name)
techage.remove_node(pos, oldnode, oldmetadata)
end,
ta5_formspec = {menu=WRENCH_MENU, ex_points=EX_POINTS},
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
local INFO = [[Commands: 'state', 'a2b', 'b2a', 'move', 'move2']]
techage.register_node({"techage:ta5_flycontroller"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
local move_xyz = M(pos):get_string("opmode") == "move xyz"
if topic == "info" then
return INFO
elseif topic == "state" then
return nvm.running and "running" or "stopped"
elseif not move_xyz and topic == "a2b" then
return fly.move_to_other_pos(pos, false)
elseif not move_xyz and topic == "b2a" then
return fly.move_to_other_pos(pos, true)
elseif not move_xyz and topic == "move" then
return fly.move_to_other_pos(pos, nvm.moveBA)
elseif move_xyz and topic == "move2" then
local line = fly.to_vector(payload, MAX_DIST)
if line then
return fly.move_to(pos, line)
end
return false
elseif topic == "reset" then
return fly.reset_move(pos)
end
return false
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
local move_xyz = M(pos):get_string("opmode") == "move xyz"
if not move_xyz and topic == 11 then
if payload[1] == 1 then
return fly.move_to_other_pos(pos, false) and 0 or 3
elseif payload[1] == 2 then
return fly.move_to_other_pos(pos, true) and 0 or 3
elseif payload[1] == 3 then
return fly.move_to_other_pos(pos, nvm.moveBA) and 0 or 3
end
elseif move_xyz and topic == 18 then -- move xyz
local line = {
x = techage.in_range(techage.beduino_signed_var(payload[1]), -1000, 1000),
y = techage.in_range(techage.beduino_signed_var(payload[2]), -1000, 1000),
z = techage.in_range(techage.beduino_signed_var(payload[3]), -1000, 1000),
}
return fly.move_to(pos, line) and 0 or 3
elseif move_xyz and topic == 24 then -- moveto xyz
local dest = {
x = techage.in_range(techage.beduino_signed_var(payload[1]), -32768, 32767),
y = techage.in_range(techage.beduino_signed_var(payload[2]), -32768, 32767),
z = techage.in_range(techage.beduino_signed_var(payload[3]), -32768, 32767),
}
return fly.move_to_abs(pos, dest, MAX_DIST) and 0 or 3
elseif move_xyz and topic == 19 then -- reset
return fly.reset_move(pos) and 0 or 3
else
return 2
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 129 then
return 0, {nvm.running and 1 or 6}
end
return 2, ""
end,
on_node_load = function(pos, node)
M(pos):set_string("status", "")
techage.get_nvm(pos).running = false
end,
})
minetest.register_craft({
output = "techage:ta5_flycontroller",
recipe = {
{"default:steel_ingot", "dye:red", "default:steel_ingot"},
{"techage:aluminum", "techage:ta5_aichip", "techage:aluminum"},
{"group:wood", "basic_materials:gear_steel", "group:wood"},
},
})
@@ -0,0 +1,94 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Gate Block to disappear
]]--
local M = minetest.get_meta
local S = techage.S
-- See also doorblock!!!
local NUM_TEXTURES = 22
local sTextures = "Wood,Aspen Wood,Jungle Wood,Pine Wood,"..
"Cobblestone,Sandstone,Stone,Desert Sandstone,"..
"Desert Stone,Silver Sandstone,Mossy Cobble,Desert Cobble,"..
"Copper,Steel,Tin,Coral,"..
"Glas,Obsidian Glas,Basalt Glass,Basalt Glass 2,"..
"Ice,Gate Wood"
local tTextures = {
["Wood"]=1, ["Aspen Wood"]=2, ["Jungle Wood"]=3, ["Pine Wood"]=4,
["Cobblestone"]=5, ["Sandstone"]=6, ["Stone"]=7, ["Desert Sandstone"]=8,
["Desert Stone"]=9, ["Silver Sandstone"]=10, ["Mossy Cobble"]=11, ["Desert Cobble"]=12,
["Copper"]=13, ["Steel"]=14, ["Tin"]=15, ["Coral"]=16,
["Glas"]=17, ["Obsidian Glas"]=18, ["Basalt Glass"]=19, ["Basalt Glass 2"]=20,
["Ice"]=21, ["Gate Wood"]=22,
}
local tPgns = {"default_wood.png", "default_aspen_wood.png", "default_junglewood.png", "default_pine_wood.png",
"default_cobble.png", "default_sandstone.png", "default_stone.png", "default_desert_sandstone.png",
"default_desert_stone_block.png", "default_silver_sandstone.png", "default_mossycobble.png", "default_desert_cobble.png",
"default_copper_block.png", "default_steel_block.png", "default_tin_block.png", "default_coral_skeleton.png",
"default_glass.png", "default_obsidian_glass.png", "techage_basalt_glass.png", "techage_basalt_glass2.png",
"default_ice.png", "techage_gate.png"}
for idx,pgn in ipairs(tPgns) do
minetest.register_node("techage:gateblock"..idx, {
description = S("TechAge Gate Block"),
tiles = {pgn},
drawtype = "glasslike",
after_place_node = function(pos, placer)
M(pos):set_string("formspec", "size[3,2]"..
"label[0,0;Select texture]"..
"dropdown[0,0.5;3;type;"..sTextures..";"..NUM_TEXTURES.."]"..
"button_exit[0.5,1.5;2,1;exit;Save]")
end,
on_receive_fields = function(pos, formname, fields, player)
local meta = minetest.get_meta(pos)
local node = minetest.get_node(pos)
if fields.type then
node.name = "techage:gateblock"..tTextures[fields.type]
minetest.swap_node(pos, node)
end
if fields.exit then
meta:set_string("formspec", "")
local number = techage.add_node(pos, node.name)
meta:set_string("infotext", S("TechAge Gate Block").." "..number)
end
end,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
end,
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = techage.BLEND,
sunlight_propagates = true,
sounds = default.node_sound_stone_defaults(),
groups = {cracky=2, choppy=2, crumbly=2, techage_door = 1,
not_in_creative_inventory = idx==NUM_TEXTURES and 0 or 1},
is_ground_content = false,
drop = "techage:gateblock"..NUM_TEXTURES,
},
techage.register_node({"techage:gateblock"..idx}, {}))
end
minetest.register_craft({
output = "techage:gateblock"..NUM_TEXTURES,
recipe = {
{"techage:basalt_glass", "", ""},
{"default:mese_crystal_fragment", "",""},
{"group:wood", "", ""},
},
})
@@ -0,0 +1,358 @@
--[[
TechAge
=======
Copyright (C) 2020-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Move Controller
]]--
-- 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 MP = minetest.get_modpath("techage")
local mark = dofile(MP .. "/basis/mark_lib.lua")
local fly = techage.flylib
local MAX_DIST = techage.maximum_move_controller_distance
local MAX_BLOCKS = techage.maximum_move_controller_blocks
local WRENCH_MENU = {
{
type = "dropdown",
choices = "0.5,1,2,4,6,8",
name = "max_speed",
label = S("Maximum Speed"),
tooltip = S("Maximum speed for moving blocks"),
default = "8",
},
{
type = "float",
name = "height",
label = S("Move block height"),
tooltip = S("Value in the range of 0.0 to 1.0"),
default = "1.0",
},
{
type = "float",
name = "offset",
label = S("Object offset"),
tooltip = S("Y-offset for non-player objects like vehicles (-0.5 to 0.5)"),
default = "0.0",
},
{
type = "dropdown",
choices = "A-B / B-A,move xyz",
name = "opmode",
label = S("Operational mode"),
tooltip = S("Switch to the remote controlled 'move xyz' mode"),
default = "A-B / B-A",
},
}
local function formspec(nvm, meta)
local status = meta:get_string("status")
local path = minetest.formspec_escape(meta:contains("path") and meta:get_string("path") or "0,3,0")
local buttons
if meta:get_string("opmode") == "move xyz" then
buttons = "field[0.4,2.3;3.8,1;path;" .. S("Move distance") .. ";" .. path .. "]" ..
"button_exit[4.1,2.0;3.8,1;move2;" .. S("Move") .. "]" ..
"button_exit[0.1,3.0;3.8,1;reset;" .. S("Reset") .. "]" ..
"button_exit[4.1,3.0;3.8,1;show;" .. S("Show positions") .. "]"
else
buttons = "field[0.4,2.3;3.8,1;path;" .. S("Move distance (A to B)") .. ";" .. path .. "]" ..
"button_exit[0.1,3.0;3.8,1;moveAB;" .. S("Move A-B") .. "]" ..
"button_exit[4.1,3.0;3.8,1;moveBA;" .. S("Move B-A") .. "]" ..
"button[4.1,2.0;3.8,1;store;" .. S("Store") .. "]" ..
"button_exit[0.1,4.0;3.8,1;show;" .. S("Show positions") .. "]" ..
"button_exit[4.1,4.0;3.8,1;reset;" .. S("Reset") .. "]"
end
return "size[8,5.5]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"box[0,-0.1;7.2,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA4 Move Controller")) .. "]" ..
techage.wrench_image(7.4, -0.05) ..
"button_exit[0.1,0.7;3.8,1;record;" .. S("Record") .. "]" ..
"button[4.1,0.7;3.8,1;done;" .. S("Done") .. "]" ..
buttons ..
"label[0.3,5.0;" .. status .. "]"
end
minetest.register_node("techage:ta4_movecontroller", {
description = S("TA4 Move Controller"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_movecontroller.png",
},
after_place_node = function(pos, placer, itemstack)
local meta = M(pos)
techage.logic.after_place_node(pos, placer, "techage:ta4_movecontroller", S("TA4 Move Controller"))
techage.logic.infotext(meta, S("TA4 Move Controller"))
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec(nvm, meta))
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if fields.record then
nvm.lpos1 = {}
nvm.lpos2 = {}
nvm.moveBA = false
nvm.recording = true
nvm.running = nil
nvm.lastpos = nil
meta:set_string("status", S("Recording..."))
local name = player:get_player_name()
minetest.chat_send_player(name, S("Click on all blocks that shall be moved"))
mark.unmark_all(name)
mark.start(name, MAX_BLOCKS)
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.done and nvm.recording then
nvm.recording = false
local name = player:get_player_name()
local pos_list = mark.get_poslist(name)
if fly.to_vector(fields.path or "", MAX_DIST) then
meta:set_string("path", fields.path)
end
local text = #pos_list.." "..S("block positions are stored.")
nvm.running = nil
nvm.lastpos = nil
meta:set_string("status", text)
nvm.lpos1 = pos_list
mark.unmark_all(name)
mark.stop(name)
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.store then
if fly.to_vector(fields.path or "", MAX_DIST) then
meta:set_string("path", fields.path)
meta:set_string("status", S("Stored"))
else
meta:set_string("status", S("Error: Invalid distance !!"))
end
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
nvm.moveBA = false
nvm.running = nil
nvm.lastpos = nil
elseif fields.moveAB then
meta:set_string("status", "")
if fly.move_to_other_pos(pos, false) then
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
end
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.moveBA then
meta:set_string("status", "")
if fly.move_to_other_pos(pos, true) then
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
mark.stop(name)
end
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.move2 then
if fly.to_vector(fields.path or "", MAX_DIST) then
meta:set_string("path", fields.path)
end
local line = fly.to_vector(meta:get_string("path"), MAX_DIST)
if line then
fly.move_to(pos, line)
end
elseif fields.reset then
fly.reset_move(pos)
nvm.running = false
elseif fields.show then
local name = player:get_player_name()
mark.mark_positions(name, nvm.lpos1, 300)
end
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if not clicker or minetest.is_protected(pos, clicker:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec(nvm, meta))
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name()
mark.unmark_all(name)
mark.stop(name)
techage.remove_node(pos, oldnode, oldmetadata)
end,
ta4_formspec = WRENCH_MENU,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
local INFO = [[Commands: 'state', 'a2b', 'b2a', 'move']]
techage.register_node({"techage:ta4_movecontroller"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
local move_xyz = M(pos):get_string("opmode") == "move xyz"
if topic == "info" then
return INFO
elseif topic == "state" then
return nvm.running and "running" or "stopped"
elseif not move_xyz and topic == "a2b" then
return fly.move_to_other_pos(pos, false)
elseif not move_xyz and topic == "b2a" then
return fly.move_to_other_pos(pos, true)
elseif not move_xyz and topic == "move" then
return fly.move_to_other_pos(pos, nvm.moveBA == false)
elseif move_xyz and topic == "move2" then
local line = fly.to_vector(payload, MAX_DIST)
if line then
return fly.move_to(pos, line)
end
return false
elseif move_xyz and topic == "moveto" then
local destpos = fly.to_vector(payload)
if destpos then
return fly.move_to_abs(pos, destpos, MAX_DIST)
end
return false
elseif topic == "reset" then
return fly.reset_move(pos)
end
return false
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
local move_xyz = M(pos):get_string("opmode") == "move xyz"
--print("on_beduino_receive_cmnd", P2S(pos), move_xyz, topic, payload[1])
if not move_xyz and topic == 11 then
if payload[1] == 1 then
return fly.move_to_other_pos(pos, false) and 0 or 3
elseif payload[1] == 2 then
return fly.move_to_other_pos(pos, true) and 0 or 3
elseif payload[1] == 3 then
return fly.move_to_other_pos(pos, nvm.moveBA == false) and 0 or 3
end
elseif move_xyz and topic == 18 then -- move xyz
local line = {
x = techage.in_range(techage.beduino_signed_var(payload[1]), -1000, 1000),
y = techage.in_range(techage.beduino_signed_var(payload[2]), -1000, 1000),
z = techage.in_range(techage.beduino_signed_var(payload[3]), -1000, 1000),
}
return fly.move_to(pos, line) and 0 or 3
elseif move_xyz and topic == 24 then -- moveto xyz
local dest = {
x = techage.in_range(techage.beduino_signed_var(payload[1]), -32768, 32767),
y = techage.in_range(techage.beduino_signed_var(payload[2]), -32768, 32767),
z = techage.in_range(techage.beduino_signed_var(payload[3]), -32768, 32767),
}
return fly.move_to_abs(pos, dest, MAX_DIST) and 0 or 3
elseif move_xyz and topic == 19 then -- reset
return fly.reset_move(pos) and 0 or 3
else
return 2
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 129 then
return 0, {nvm.running and 1 or 6}
end
return 2, ""
end,
on_node_load = function(pos, node)
M(pos):set_string("teleport_mode", "") -- delete not working (legacy) op mode
M(pos):set_string("status", "")
techage.get_nvm(pos).running = false
end,
})
minetest.register_node("techage:rack_and_pinion", {
description = S("TA Rack and Pinion"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"techage_rack_and_pinion.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -6/32, -16/32, 14.1/32, 6/32, 16/32, 16/32},
},
},
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
paramtype2 = "facedir",
is_ground_content = false,
groups = {cracky = 1, level = 2},
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:moveblock", {
description = "Techage Invisible Move Block",
drawtype = "glasslike_framed_optional",
inventory_image = 'techage_inv_invisible.png',
tiles = {"blank.png"},
selection_box = {
type = "fixed",
fixed = {
{-16/32, -16/32, -16/32, 16/32, -14/32, 16/32},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
walkable = false,
pointable = true,
is_ground_content = false,
groups = {cracky = 3, oddly_breakable_by_hand = 3, not_in_creative_inventory = 1},
sounds = default.node_sound_glass_defaults(),
})
minetest.register_craft({
output = "techage:ta4_movecontroller",
recipe = {
{"default:steel_ingot", "dye:blue", "default:steel_ingot"},
{"default:mese_crystal_fragment", "techage:ta4_wlanchip", "default:mese_crystal_fragment"},
{"group:wood", "basic_materials:gear_steel", "group:wood"},
},
})
minetest.register_craft({
output = "techage:rack_and_pinion 10",
recipe = {
{"", "default:steel_ingot", ""},
{"basic_materials:steel_bar", "default:steel_ingot", "basic_materials:steel_bar"},
{"", "default:steel_ingot", ""},
},
})
@@ -0,0 +1,292 @@
--[[
TechAge
=======
Copyright (C) 2020-2025 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Move Controller II (replaces the ta4_movecontroller)
]]--
-- 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 MP = minetest.get_modpath("techage")
local mark = dofile(MP .. "/basis/mark_lib.lua")
local fly = techage.flylib2
local MAX_DIST = techage.maximum_move_controller_distance
local MAX_BLOCKS = 16
local WRENCH_MENU = {
{
type = "dropdown",
choices = "0.5,1,2,4,6,8",
name = "max_speed",
label = S("Maximum Speed"),
tooltip = S("Maximum speed for moving blocks"),
default = "8",
},
{
type = "float",
name = "height",
label = S("Move block height"),
tooltip = S("Value in the range of 0.0 to 1.0"),
default = "1.0",
},
{
type = "float",
name = "offset",
label = S("Object offset"),
tooltip = S("Y-offset for non-player objects like vehicles (-0.5 to 0.5)"),
default = "0.0",
},
}
local function formspec1(nvm, meta)
local status = meta:get_string("status")
local base_pos = nvm.lNodes and nvm.lNodes[1] and nvm.lNodes[1].base_pos or vector.zero()
base_pos = " " .. P2S(base_pos) or ""
return "size[8,7.5]" ..
"tabheader[0,0;tab;" .. S("Control,Inventory") .. ";1;;true]" ..
"box[0,-0.1;7.2,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA4 Move Controller")) .. "]" ..
techage.wrench_image(7.4, -0.05) ..
"button[0.1,0.7;3.8,1;record;" .. S("Record") .. "]" ..
"button[4.1,0.7;3.8,1;done;" .. S("Done") .. "]" ..
"button_exit[0.1,2.0;3.8,1;show;" .. S("Show start positions") .. "]" ..
"label[4.1,2.2;" .. S("Pos 1:") .. base_pos .. "]" ..
"button_exit[0.1,3.3;3.8,1;move;" .. S("Test move") .. "]" ..
"button_exit[4.1,3.3;3.8,1;reset;" .. S("Reset") .. "]" ..
"label[0.3,5.0;" .. status .. "]"
end
local function presets(nvm, inv, idx, x, y)
local node = nvm.lNodes[idx]
local slot = inv:get_stack("main", idx)
if node then
if slot:is_empty() then
return "item_image[" .. x .. "," .. y .. ";1,1;" .. node.name .. "]" ..
"image[" .. x .. "," .. y .. ";1,1;techage_white_frame.png]"
end
end
return ""
end
local function tooltips(nvm, inv, idx, x, y)
local node = nvm.lNodes[idx]
local slot = inv:get_stack("main", idx)
if node then
if slot:is_empty() then
if node.curr_pos then
return "tooltip[" .. x .. "," .. y .. ";1,1;" .. S("Node at pos") .. ": " .. P2S(node.curr_pos) .. ";#0C3D32;#FFFFFF]"
else
return "tooltip[" .. x .. "," .. y .. ";1,1;" .. S("missing") .. ";#0C3D32;#FFFFFF]"
end
end
end
return ""
end
local function formspec2(nvm, meta)
local tbl = {}
local inv = meta:get_inventory()
nvm.lNodes = nvm.lNodes or {}
for idx = 1,MAX_BLOCKS do
local x = ((idx-1) % 8) + 0.3
local y = math.floor((idx-1) / 8) * 2.4
tbl[#tbl+1] = "label[" .. x .."," .. y .. ";" .. idx .. "]"
x = ((idx-1) % 8)
y = math.floor((idx-1) / 8) + 0.5
tbl[#tbl+1] = presets(nvm, inv, idx, x, y)
tbl[#tbl+1] = tooltips(nvm, inv, idx, x, y)
end
return "size[8,7]" ..
"tabheader[0,0;tab;" .. S("Control,Inventory") .. ";2;;true]" ..
table.concat(tbl, "") ..
"list[context;main;0,0.5;8,2;]" ..
"list[current_player;main;0,3.3;8,4;]" ..
"listring[context;main]" ..
"listring[current_player;main]"
end
minetest.register_node("techage:ta4_movecontroller2", {
description = S("TA4 Move Controller II"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_movecontroller.png",
},
after_place_node = function(pos, placer, itemstack)
local meta = M(pos)
local inv = meta:get_inventory()
inv:set_size('main', MAX_BLOCKS)
techage.logic.after_place_node(pos, placer, "techage:ta4_movecontroller2", S("TA4 Move Controller II"))
techage.logic.infotext(meta, S("TA4 Move Controller II"))
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec1(nvm, meta))
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if fields.tab == "2" then
meta:set_string("formspec", formspec2(nvm, meta))
return
elseif fields.tab == "1" then
meta:set_string("formspec", formspec1(nvm, meta))
return
elseif fields.record then
nvm.recording = true
nvm.running = nil
meta:set_string("status", S("Recording..."))
local name = player:get_player_name()
minetest.chat_send_player(name, S("Click on all blocks that shall be moved"))
mark.unmark_all(name)
mark.start(name, MAX_BLOCKS)
meta:set_string("formspec", formspec1(nvm, meta))
elseif fields.done and nvm.recording then
nvm.recording = false
local name = player:get_player_name()
local pos_list = mark.get_poslist(name)
local text = #pos_list.." "..S("block positions are stored.")
nvm.running = nil
meta:set_string("status", text)
nvm.lNodes = fly.get_nodes(pos_list)
mark.unmark_all(name)
mark.stop(name)
meta:set_string("formspec", formspec1(nvm, meta))
elseif fields.move then
nvm.lNodes = nvm.lNodes or {}
local node = nvm.lNodes[1]
if node then
local dest_pos = {x = node.base_pos.x, y = node.base_pos.y + 5, z = node.base_pos.z}
fly.move_nodes(pos, nvm, dest_pos, 0)
end
elseif fields.reset then
fly.reset_nodes(pos, nvm, 0)
elseif fields.show then
local name = player:get_player_name()
local lpos = fly.get_node_base_positions(nvm.lNodes or {})
mark.mark_positions(name, lpos, 300)
end
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if not clicker or minetest.is_protected(pos, clicker:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec1(nvm, meta))
end,
allow_metadata_inventory_move = function() return 0 end,
allow_metadata_inventory_take = function() return 0 end,
allow_metadata_inventory_put = function() return 0 end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name()
mark.unmark_all(name)
mark.stop(name)
techage.remove_node(pos, oldnode, oldmetadata)
end,
ta4_formspec = WRENCH_MENU,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
local INFO = [[Commands: 'state', 'moveto']]
techage.register_node({"techage:ta4_movecontroller2"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
nvm.lNodes = nvm.lNodes or {}
if topic == "info" then
return INFO
elseif topic == "state" then
return nvm.running and "running" or "stopped"
elseif topic == "moveto" then
local destpos = fly.get_pos(payload)
if destpos then
if fly.valid_distance(nvm, destpos, 0, MAX_DIST) then
return fly.move_nodes(pos, nvm, destpos, 0)
else
M(pos):set_string("status", S("Distance too large!"))
end
else
M(pos):set_string("status", S("Command syntax error!"))
end
return false
elseif topic == "getpos" then
if nvm.lNodes[1] then
local cpos = nvm.lNodes[1].curr_pos
local spos = string.sub(P2S(cpos), 2, -2)
return spos
end
elseif topic == "reset" then
return fly.reset_nodes(pos, nvm, 0)
end
return false
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
nvm.lNodes = nvm.lNodes or {}
if topic == 24 then -- moveto xyz
local destpos = {
x = techage.in_range(techage.beduino_signed_var(payload[1]), -32768, 32767),
y = techage.in_range(techage.beduino_signed_var(payload[2]), -32768, 32767),
z = techage.in_range(techage.beduino_signed_var(payload[3]), -32768, 32767),
}
if fly.valid_distance(nvm, destpos, 0, MAX_DIST) then
return fly.move_nodes(pos, nvm, destpos, 0) and 0 or 3
else
M(pos):set_string("status", S("Distance too large!"))
return 3
end
elseif topic == 19 then -- reset
return fly.reset_nodes(pos, nvm, 0) and 0 or 3
else
return 2
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 129 then
return 0, {nvm.running and 1 or 6}
end
return 2, ""
end,
on_node_load = function(pos, node)
M(pos):set_string("status", "")
techage.get_nvm(pos).running = false
--print("techage.was_normal_shutdown()", techage.was_normal_shutdown())
end,
})
minetest.register_craft({
output = "techage:ta4_movecontroller2",
recipe = {"techage:ta4_movecontroller"},
type = "shapeless",
})
@@ -0,0 +1,149 @@
--[[
TechAge
=======
Copyright (C) 2021-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Sound Block
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local t = {}
for idx, ogg in ipairs(techage.OggFileList) do
t[idx] = idx .. "," .. ogg
end
local OGG_FILES = table.concat(t, ",")
local logic = techage.logic
local GAIN = {0.05 ,0.1, 0.2, 0.5, 1.0}
local function play_sound(pos, ogg, gain)
minetest.sound_play(ogg, {
pos = pos,
gain = GAIN[gain or 1] or 1,
max_hear_distance = 15})
end
local function formspec(meta)
local idx = meta:contains("idx") and meta:get_int("idx") or 1
local gain = meta:contains("gain") and meta:get_int("gain") or 1
return "size[8,8]"..
"tablecolumns[text,width=5;text]"..
"table[0,0;8,6;oggfiles;" .. OGG_FILES .. ";" .. idx .. "]" ..
"dropdown[0,6.5;5.5,1.4;gain;1,2,3,4,5;" .. gain .. "]" ..
"button[2.5,7.2;3,1;play;" .. S("Play") .. "]"
end
local function play_predefined_sound(pos)
local mem = techage.get_mem(pos)
if not mem.blocking_time or (mem.blocking_time < minetest.get_gametime()) then
local idx = M(pos):get_int("idx")
local ogg = techage.OggFileList[idx or 1] or techage.OggFileList[1]
local gain = M(pos):get_int("gain")
play_sound(pos, ogg, gain)
mem.blocking_time = minetest.get_gametime() + 2
return true
end
end
minetest.register_node("techage:ta3_soundblock", {
description = S("TA3 Sound Block"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3_top.png",
"techage_filling_ta3.png^techage_frame_ta3_top.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_sound.png",
},
after_place_node = function(pos, placer)
local meta = M(pos)
logic.after_place_node(pos, placer, "techage:ta3_soundblock", S("TA3 Sound Block"))
logic.infotext(meta, S("TA3 Sound Block"))
meta:set_string("formspec", formspec(meta))
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
if fields.oggfiles then
local mem = techage.get_mem(pos)
local t = minetest.explode_table_event(fields.oggfiles)
mem.idx = t.row
end
if fields.gain then
M(pos):set_int("gain", tonumber(fields.gain) or 1)
end
if fields.play then
local mem = techage.get_mem(pos)
M(pos):set_int("idx", mem.idx or 1)
local ogg = techage.OggFileList[mem.idx or 1] or techage.OggFileList[1]
play_sound(pos, ogg, M(pos):get_int("gain"))
end
end,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
local INFO = [[Commands: 'on', 'sound', 'gain']]
techage.register_node({"techage:ta3_soundblock"}, {
on_recv_message = function(pos, src, topic, payload)
if topic == "info" then
return INFO
elseif topic == "on" then
play_predefined_sound(pos)
elseif topic == "sound" then
M(pos):set_int("idx", tonumber(payload or 1) or 1)
elseif topic == "gain" then
M(pos):set_int("gain", tonumber(payload or 1) or 1)
else
return "unsupported"
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
print("ta3_soundblock", topic, payload[1], payload[2])
if topic == 1 then
if payload[1] == 1 then
play_predefined_sound(pos)
return 0
end
elseif topic == 14 then
if payload[1] == 1 then
M(pos):set_int("gain", payload[2])
return 0
elseif payload[1] == 2 then
M(pos):set_int("idx", payload[2])
return 0
end
end
return 2 -- unknown or invalid topic
end,
on_node_load = function(pos)
local meta = M(pos)
meta:set_string("formspec", formspec(meta))
end
})
minetest.register_craft({
output = "techage:ta3_soundblock",
recipe = {
{"", "group:wood",""},
{"techage:vacuum_tube", "basic_materials:gold_wire", "techage:usmium_nuggets"},
{"", "group:wood", ""},
},
})
@@ -0,0 +1,207 @@
--[[
TechAge
=======
Copyright (C) 2020-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Turn Controller
]]--
-- 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 MP = minetest.get_modpath("techage")
local mark = dofile(MP .. "/basis/mark_lib.lua")
local fly = techage.flylib
local MAX_BLOCKS = 16
local function formspec(nvm, meta)
local status = meta:get_string("status")
local path = meta:contains("path") and meta:get_string("path") or "0,3,0"
return "size[8,3]" ..
"box[0,-0.1;7.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA4 Turn Controller")) .. "]" ..
--techage.wrench_image(7.4, -0.05) ..
"button[0.1,0.7;3.8,1;record;" .. S("Record") .. "]" ..
"button[4.1,0.7;3.8,1;done;" .. S("Done") .. "]" ..
"button[0.1,1.5;3.8,1;left;" .. S("Turn left") .. "]" ..
"button[4.1,1.5;3.8,1;right;" .. S("Turn right") .. "]" ..
"label[0.3,2.5;" .. status .. "]"
end
minetest.register_node("techage:ta4_turncontroller", {
description = S("TA4 Turn Controller"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_turn.png",
},
after_place_node = function(pos, placer, itemstack)
local meta = M(pos)
techage.logic.after_place_node(pos, placer, "techage:ta4_turncontroller", S("TA4 Turn Controller"))
techage.logic.infotext(meta, S("TA4 Turn Controller"))
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec(nvm, meta))
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if fields.record then
nvm.lpos1 = {}
nvm.lpos2 = {}
meta:set_string("status", S("Recording..."))
local name = player:get_player_name()
minetest.chat_send_player(name, S("Click on all blocks that shall be turned"))
mark.start(name, MAX_BLOCKS)
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.done then
local name = player:get_player_name()
local pos_list = mark.get_poslist(name)
local text = #pos_list.." "..S("block positions are stored.")
meta:set_string("status", text)
nvm.lpos = pos_list
mark.unmark_all(name)
mark.stop(name)
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.left then
meta:set_string("status", "")
if nvm.lpos then
local new_posses = fly.rotate_nodes(pos, nvm.lpos, "l")
if new_posses then
nvm.lpos = new_posses
local name = player:get_player_name()
mark.stop(name)
end
end
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.right then
meta:set_string("status", "")
if nvm.lpos then
local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r")
if new_posses then
nvm.lpos = new_posses
local name = player:get_player_name()
mark.stop(name)
end
end
meta:set_string("formspec", formspec(nvm, meta))
end
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name()
mark.unmark_all(name)
mark.stop(name)
techage.remove_node(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
local INFO = [[Commands: 'left', 'right', 'uturn']]
techage.register_node({"techage:ta4_turncontroller"}, {
on_recv_message = function(pos, src, topic, payload)
if topic == "info" then
return INFO
elseif topic == "left" then
local nvm = techage.get_nvm(pos)
local new_posses = fly.rotate_nodes(pos, nvm.lpos, "l")
if new_posses then
nvm.lpos = new_posses
return true
end
return false
elseif topic == "right" then
local nvm = techage.get_nvm(pos)
local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r")
if new_posses then
nvm.lpos = new_posses
return true
end
return false
elseif topic == "uturn" then
local nvm = techage.get_nvm(pos)
local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r")
if new_posses then
nvm.lpos = new_posses
new_posses = fly.rotate_nodes(pos, nvm.lpos, "r")
if new_posses then
nvm.lpos = new_posses
return true
end
end
return false
end
return false
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 12 then
if payload[1] == 1 then
local nvm = techage.get_nvm(pos)
local new_posses = fly.rotate_nodes(pos, nvm.lpos, "l")
if new_posses then
nvm.lpos = new_posses
return 0
end
return 3
elseif payload[1] == 2 then
local nvm = techage.get_nvm(pos)
local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r")
if new_posses then
nvm.lpos = new_posses
return 0
end
return 3
elseif payload[1] == 3 then
local nvm = techage.get_nvm(pos)
local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r")
if new_posses then
nvm.lpos = new_posses
new_posses = fly.rotate_nodes(pos, nvm.lpos, "r")
if new_posses then
nvm.lpos = new_posses
return 0
end
end
return 3
end
return 2
else
return 2
end
end,
on_node_load = function(pos, node)
M(pos):set_string("status", "")
end,
})
minetest.register_craft({
output = "techage:ta4_turncontroller",
recipe = {
{"default:steel_ingot", "dye:blue", "default:steel_ingot"},
{"techage:aluminum", "techage:baborium_ingot", "techage:aluminum"},
{"group:wood", "basic_materials:gear_steel", "group:wood"},
},
})