built on 04/02/2023 15:45:23
This commit is contained in:
parent
e4f4a04f0b
commit
1088fb8bfb
@ -212,8 +212,12 @@ minetest.register_node("hyperloop:shaft2", {
|
||||
light_source = 2,
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
----- To be unbreakable -----
|
||||
on_blast = function() end,
|
||||
on_destruct = function () end,
|
||||
can_dig = function() return false end,
|
||||
diggable = false,
|
||||
groups = {cracky = 1, not_in_creative_inventory=1},
|
||||
groups = {cracky = 1, not_in_creative_inventory=1, unbreakable=1},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
@ -255,8 +259,12 @@ minetest.register_node("hyperloop:shaftA2", {
|
||||
light_source = 2,
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
----- To be unbreakable -----
|
||||
on_blast = function() end,
|
||||
on_destruct = function () end,
|
||||
can_dig = function() return false end,
|
||||
diggable = false,
|
||||
groups = {cracky = 1, not_in_creative_inventory=1},
|
||||
groups = {cracky = 1, not_in_creative_inventory=1, unbreakable=1},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
|
@ -173,8 +173,12 @@ minetest.register_node("hyperloop:tubeS2", {
|
||||
light_source = 2,
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
----- To be unbreakable -----
|
||||
on_blast = function() end,
|
||||
on_destruct = function () end,
|
||||
can_dig = function() return false end,
|
||||
diggable = false,
|
||||
groups = {cracky = 1, not_in_creative_inventory=1},
|
||||
groups = {cracky = 1, not_in_creative_inventory=1, unbreakable=1},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
@ -263,8 +267,12 @@ minetest.register_node("hyperloop:tubeA2", {
|
||||
light_source = 2,
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
----- To be unbreakable -----
|
||||
on_blast = function() end,
|
||||
on_destruct = function () end,
|
||||
can_dig = function() return false end,
|
||||
diggable = false,
|
||||
groups = {cracky = 1, not_in_creative_inventory=1},
|
||||
groups = {cracky = 1, not_in_creative_inventory=1, unbreakable=1},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
|
@ -44,6 +44,7 @@ The mod features are:
|
||||
- Ingame documentation (German and English), based on the mod "doc"
|
||||
- API to register carts from other mods
|
||||
- chat command '/mycart <num>' to output cart state and location
|
||||
- Command interface for Techage (Lua and ICTA) and for Beduino Controllers
|
||||
|
||||
|
||||
Technical Background
|
||||
@ -118,6 +119,45 @@ The "No speed limit" sign can be used to remove the speed limit.
|
||||
The speed limit signs must be placed next to the track so that they can
|
||||
be read from the cart. This allows different speeds in each direction of travel.
|
||||
|
||||
## Command Interface
|
||||
|
||||
### Techage ICTA Controller
|
||||
|
||||
The ICTA Controller support the conditions:
|
||||
|
||||
- "read cart state" (function returns "stopped" or "running")
|
||||
- "read cart location" (function returns the distance or the station/buffer name)
|
||||
|
||||
See help page of the ICTA controller block.
|
||||
|
||||
### Techage Lua Controller
|
||||
|
||||
The Lua controller support the functions:
|
||||
|
||||
- `$cart_state(num)` (function returns "stopped" or "running")
|
||||
- `$cart_location(num)` (function returns the distance or the station/buffer name)
|
||||
|
||||
See help page of the Lua controller block.
|
||||
|
||||
### Cart Terminal
|
||||
|
||||
The Cart Terminal has a Techage command interface with the commands:
|
||||
|
||||
| Command | Data | Description |
|
||||
| ---------- | ---------- | ------------------------------------------------------- |
|
||||
| `state` | \<cart-ID> | Returns `unknown`, `stopped`, or `running` |
|
||||
| `distance` | \<cart-ID> | Returns the distance from the cart to the Cart Terminal |
|
||||
|
||||
### Beduino Controller
|
||||
|
||||
The Cart Terminal has a Beduino command interface with the commands:
|
||||
|
||||
| Command | Topic | Data | Response | Description |
|
||||
| -------- | ----- | --------- | ---------- | ------------------------------------------------------- |
|
||||
| State | 129 | [cart-id] | [state] | Returns 0 = UNKNOWN, 1 = STOPPED, 2 = RUNNING |
|
||||
| Distance | 130 | [cart-id] | [distance] | Returns the distance from the cart to the Cart Terminal |
|
||||
|
||||
|
||||
|
||||
Migration to v2
|
||||
---------------
|
||||
@ -153,3 +193,4 @@ History
|
||||
Speed limit signs and cart terminal added
|
||||
2021-09-02 V2.01 Chat command /stopcart added
|
||||
2021-10-18 V2.02 Cart reproduction bug fixed
|
||||
2023-01-04 V2.03 Techage and Beduino command interface added
|
93
minecart/beduino.lua
Normal file
93
minecart/beduino.lua
Normal file
@ -0,0 +1,93 @@
|
||||
--[[
|
||||
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2023 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
|
||||
]]--
|
||||
|
||||
local minecart_lib = [[
|
||||
// Minecart library for reading status and distance
|
||||
// from running carts. To do this, a cart terminal
|
||||
// must be connected to an I/O Module.
|
||||
|
||||
import "lib/techage.c"
|
||||
|
||||
var payload[1];
|
||||
var resp[1];
|
||||
|
||||
|
||||
// Read cart state.
|
||||
// Parameters:
|
||||
// - ip_port: IOM port to the Cart Terminal
|
||||
// - card_id: Cart number
|
||||
// Function returns:
|
||||
// - 0 for unknown/missing
|
||||
// - 1 for stopped
|
||||
// - 2 for running
|
||||
func mc_get_state(io_port, cart_id) {
|
||||
var sts;
|
||||
|
||||
payload[0] = cart_id;
|
||||
request_data(io_port, 129, payload, resp);
|
||||
if(sts == 0) {
|
||||
return resp[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read cart distance.
|
||||
// Parameters:
|
||||
// - ip_port: IOM port to the Cart Terminal
|
||||
// - card_id: Cart number
|
||||
// Function returns the distance between
|
||||
// Cart Terminal and cart in meter.
|
||||
func mc_get_distance(io_port, cart_id) {
|
||||
var sts;
|
||||
|
||||
payload[0] = cart_id;
|
||||
request_data(io_port, 130, payload, resp);
|
||||
if(sts == 0) {
|
||||
return resp[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
]]
|
||||
|
||||
local minecart_demo = [[
|
||||
import "sys/stdio.asm"
|
||||
import "sys/os.c"
|
||||
import "lib/minecart.c"
|
||||
|
||||
func init() {
|
||||
setstdout(1); // use terminal window for stdout
|
||||
putstr("### Minecart Demo ###\n");
|
||||
}
|
||||
|
||||
func cart_state(io_port, cart_id) {
|
||||
putstr("Cart #");
|
||||
putnum(cart_id);
|
||||
putstr(": state = ");
|
||||
putnum(mc_get_state(io_port, cart_id));
|
||||
putstr(", distance = ");
|
||||
putnum(mc_get_distance(io_port, cart_id));
|
||||
putstr("\n");
|
||||
}
|
||||
|
||||
func loop() {
|
||||
// Adapt IO port and cart ID to your needs
|
||||
cart_state(0, 1);
|
||||
sleep(20);
|
||||
}
|
||||
]]
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
if minetest.global_exists("vm16") and minetest.global_exists("beduino") then
|
||||
vm16.register_ro_file("beduino", "lib/minecart.c", minecart_lib)
|
||||
vm16.register_ro_file("beduino", "demo/minecart.c", minecart_demo)
|
||||
end
|
||||
end)
|
@ -94,8 +94,8 @@ function minecart.untake_items(pos, param2, stack)
|
||||
local def = RegisteredInventories[node.name]
|
||||
local inv = minetest.get_inventory({type="node", pos=npos})
|
||||
|
||||
if def and inv and def.put_listname then
|
||||
return inv:add_item(def.put_listname, stack)
|
||||
if def and inv and def.take_listname then
|
||||
return inv:add_item(def.take_listname, stack)
|
||||
elseif def and def.untake_item then
|
||||
return def.untake_item(npos, stack)
|
||||
else
|
||||
|
@ -3,7 +3,7 @@
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2021 Joachim Stolberg
|
||||
Copyright (C) 2019-2023 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
@ -13,7 +13,7 @@
|
||||
minecart = {}
|
||||
|
||||
-- Version for compatibility checks, see readme.md/history
|
||||
minecart.version = 2.02
|
||||
minecart.version = 2.03
|
||||
|
||||
minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false
|
||||
minecart.teleport_enabled = minetest.settings:get_bool("minecart_teleport_enabled") == true
|
||||
@ -39,6 +39,7 @@ dofile(MP .. "/protection.lua")
|
||||
dofile(MP .. "/signs.lua")
|
||||
dofile(MP .. "/terminal.lua")
|
||||
dofile(MP .. "/pusher.lua")
|
||||
dofile(MP .. "/beduino.lua")
|
||||
|
||||
if minecart.hopper_enabled then
|
||||
dofile(MP .. "/hopper.lua")
|
||||
|
@ -3,7 +3,7 @@
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2021 Joachim Stolberg
|
||||
Copyright (C) 2019-2023 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
@ -90,7 +90,22 @@ local function get_cart_state_and_loc(name, userID, query_pos)
|
||||
end
|
||||
end
|
||||
return "unknown", 0, "unknown"
|
||||
end
|
||||
end
|
||||
|
||||
-- Return the cart distance to the query_pos.
|
||||
local function get_cart_distance(name, userID, query_pos)
|
||||
if tCartsOnRail[name] and tCartsOnRail[name][userID] then
|
||||
local cart = tCartsOnRail[name][userID]
|
||||
if cart.last_pos or cart.pos then
|
||||
if cart.objID == 0 then -- stopped
|
||||
return math.floor(vector.distance(cart.pos or cart.last_pos, query_pos))
|
||||
else
|
||||
return math.floor(vector.distance(cart.last_pos or cart.pos, query_pos))
|
||||
end
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
local function get_cart_info(owner, userID, query_pos)
|
||||
local state, loc, name = get_cart_state_and_loc(owner, userID, query_pos)
|
||||
@ -318,6 +333,10 @@ function minecart.cmnd_cart_location(name, userID, query_pos)
|
||||
return loc
|
||||
end
|
||||
|
||||
function minecart.cmnd_cart_distance(name, userID, query_pos)
|
||||
return get_cart_distance(name, userID, query_pos)
|
||||
end
|
||||
|
||||
function minecart.get_cart_list(pos, name)
|
||||
local userIDs = {}
|
||||
local carts = {}
|
||||
|
@ -3,7 +3,7 @@
|
||||
Minecart
|
||||
========
|
||||
|
||||
Copyright (C) 2019-2021 Joachim Stolberg
|
||||
Copyright (C) 2019-2023 Joachim Stolberg
|
||||
|
||||
MIT
|
||||
See license.txt for more information
|
||||
@ -59,6 +59,11 @@ minetest.register_node("minecart:terminal", {
|
||||
local meta = M(pos)
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
meta:set_string("formspec", formspec(pos, ""))
|
||||
if minetest.global_exists("techage") then
|
||||
local number = techage.add_node(pos, "minecart:terminal")
|
||||
meta:set_string("node_number", number)
|
||||
meta:set_string("infotext", "Cart Terminal " .. number)
|
||||
end
|
||||
minetest.get_node_timer(pos):start(2)
|
||||
end,
|
||||
|
||||
@ -88,3 +93,42 @@ minetest.register_craft({
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
if minetest.global_exists("techage") then
|
||||
techage.register_node({"minecart:terminal"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local number = tonumber(payload)
|
||||
if number then
|
||||
local owner = M(pos):get_string("owner")
|
||||
if topic == "state" then
|
||||
return minecart.cmnd_cart_state(owner, number)
|
||||
elseif topic == "distance" then
|
||||
return minecart.cmnd_cart_distance(owner, number, pos)
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
return 2 -- unknown or invalid topic
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 128 then
|
||||
return 0, "minecart:terminal"
|
||||
elseif topic == 129 then -- state
|
||||
local owner = M(pos):get_string("owner")
|
||||
local STATE = {unknown = 0, stopped = 1, running = 2}
|
||||
local state = STATE[minecart.cmnd_cart_state(owner, payload[1])] or 0
|
||||
return 0, {state}
|
||||
elseif topic == 130 then -- distance
|
||||
local owner = M(pos):get_string("owner")
|
||||
local dist = minecart.cmnd_cart_distance(owner, payload[1], pos)
|
||||
return 0, {dist}
|
||||
else
|
||||
return 2, "" -- topic is unknown or invalid
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
end)
|
@ -268,9 +268,11 @@ signs_bot.register_botcommand("fall_down", {
|
||||
local sts, pos3 = minetest.line_of_sight(pos1, pos2)
|
||||
if sts == false then
|
||||
sts, _ = minetest.spawn_falling_node(mem.robot_pos)
|
||||
mem.stored_node = get_node_lvm(pos3)
|
||||
minetest.swap_node(pos3, {name="air"})
|
||||
if sts then
|
||||
mem.bot_falling = 2
|
||||
mem.robot_pos = {x=pos3.x, y=pos3.y+1, z=pos3.z}
|
||||
mem.robot_pos = {x=pos3.x, y=pos3.y, z=pos3.z}
|
||||
return signs_bot.BUSY
|
||||
end
|
||||
end
|
||||
|
@ -52,7 +52,7 @@ end
|
||||
if farming.mod == "redo" then
|
||||
local fp_grows = function(def, step)
|
||||
local crop = def.crop .. "_" .. step
|
||||
local node = minetest.registered_nodes[crop]
|
||||
local node = minetest.registered_nodes[crop]
|
||||
if node then
|
||||
fp(def.seed, def.crop .. "_1", crop, def.trellis)
|
||||
return node.groups and node.groups.growing
|
||||
@ -63,7 +63,9 @@ if farming.mod == "redo" then
|
||||
-- everything except cocoa (these can only be placed on jungletree)
|
||||
if name ~= "farming:cocoa_beans" then
|
||||
local step = def.steps
|
||||
while fp_grows(def, step) do step = step + 1 end
|
||||
if step then
|
||||
while fp_grows(def, step) do step = step + 1 end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -89,6 +89,19 @@ Available worlds will be converted to 'lsqlite3', but there is no way back, so:
|
||||
|
||||
### History
|
||||
|
||||
**2023-02-04 V1.10**
|
||||
- Improve flycontroller
|
||||
- Remove handover for movecontroller
|
||||
- Rename "techage:signal_lamp" to "techage:color_lamp"
|
||||
- Rename "techage:signal_lamp2" to "techage:color_lamp2"
|
||||
- Add countdown mode to TA4 Detector
|
||||
- Adapt to new beduino and minecart versions
|
||||
- Improve manuals
|
||||
- flycontroller/movecontroller: Allow moving blocks through unloaded areas
|
||||
- playerdetector: Add wrench menu to configure search radius
|
||||
- Default furnace: Don't use items filled from the top as fuel
|
||||
- Many further improvements and bug fixes from joe7575 and Niklp09
|
||||
|
||||
**2022-09-03 V1.09**
|
||||
- Change the way items are pushed
|
||||
- Add "Flow Limiter" mode to TA4 pump and TA4 pusher
|
||||
|
@ -266,6 +266,11 @@ if techage.max_num_forceload_blocks > 0 then
|
||||
output = "techage:forceloadtile",
|
||||
recipe = {"techage:forceload"},
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "techage:forceload",
|
||||
recipe = {"techage:forceloadtile"},
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
|
@ -17,7 +17,7 @@ local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
-- Consumer Related Data
|
||||
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
|
||||
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer or {} end
|
||||
|
||||
local STANDBY_TICKS = 3
|
||||
local COUNTDOWN_TICKS = 4
|
||||
|
@ -341,7 +341,7 @@ local tubing = {
|
||||
CRD(pos).State:stop(pos, nvm)
|
||||
config_item(pos, payload)
|
||||
return 0
|
||||
elseif topic == 68 then -- Set push limit
|
||||
elseif topic == 68 or topic == 20 then -- Set push limit
|
||||
local nvm = techage.get_nvm(pos)
|
||||
CRD(pos).State:stop(pos, nvm)
|
||||
set_limit(pos, nvm, payload[1])
|
||||
|
@ -196,6 +196,9 @@ local function quarry_task(pos, crd, nvm)
|
||||
pos1.y = y_curr
|
||||
pos2.y = y_curr
|
||||
|
||||
-- Restarting the server can detach the coroutine data.
|
||||
-- Therefore, read nvm again.
|
||||
nvm = techage.get_nvm(pos)
|
||||
nvm.level = y_first - y_curr
|
||||
|
||||
if minetest.is_area_protected(pos1, pos2, owner, 5) then
|
||||
@ -382,6 +385,11 @@ local tubing = {
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
CRD(pos).State:on_node_load(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if nvm.techage_state == techage.RUNNING then
|
||||
stop_sound(pos)
|
||||
play_sound(pos)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
|
@ -346,6 +346,20 @@ local function count_number_of_chests(pos)
|
||||
M(pos):set_int("stacksize", STACK_SIZE * cnt)
|
||||
end
|
||||
|
||||
local function dummy_chest_behind(pos, node)
|
||||
local dir = techage.side_to_outdir("B", node.param2)
|
||||
local pos1 = tubelib2.get_pos(pos, dir)
|
||||
node = techage.get_node_lvm(pos1)
|
||||
return node.name == "techage:ta4_chest_dummy"
|
||||
end
|
||||
|
||||
local function part_of_a_chain(pos, node)
|
||||
local dir = techage.side_to_outdir("F", node.param2)
|
||||
local pos1 = tubelib2.get_pos(pos, dir)
|
||||
node = techage.get_node_lvm(pos1)
|
||||
return node.name == "techage:ta4_chest_dummy" or node.name == "techage:ta4_chest"
|
||||
end
|
||||
|
||||
local function search_chest_in_front(pos, node)
|
||||
local dir = techage.side_to_outdir("F", node.param2)
|
||||
local pos1 = tubelib2.get_pos(pos, dir)
|
||||
@ -529,6 +543,10 @@ minetest.register_node("techage:ta4_chest", {
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local node = minetest.get_node(pos)
|
||||
if dummy_chest_behind(pos, node) then
|
||||
minetest.remove_node(pos)
|
||||
return true
|
||||
end
|
||||
if search_chest_in_front(pos, node) then
|
||||
node.name = "techage:ta4_chest_dummy"
|
||||
minetest.swap_node(pos, node)
|
||||
@ -667,6 +685,18 @@ techage.register_node({"techage:ta4_chest_dummy"}, {
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Repair Dummy Chests",
|
||||
name = "techage:chest_dummy",
|
||||
nodenames = {"techage:ta4_chest_dummy"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
if not part_of_a_chain(pos, node) then
|
||||
minetest.swap_node(pos, {name = "techage:ta4_chest", param2 = node.param2})
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "techage:ta4_chest",
|
||||
|
@ -3,7 +3,7 @@
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2020-2022 Joachim Stolberg
|
||||
Copyright (C) 2020-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
@ -30,26 +30,6 @@ local function lvect_add_vec(lvect1, offs)
|
||||
return lvect2
|
||||
end
|
||||
|
||||
local function lvect_add(lvect1, lvect2)
|
||||
if not lvect1 or not lvect2 then return end
|
||||
|
||||
local lvect3 = {}
|
||||
for i, v in ipairs(lvect1) do
|
||||
lvect3[#lvect3 + 1] = vector.add(v, lvect2[i])
|
||||
end
|
||||
return lvect3
|
||||
end
|
||||
|
||||
local function lvect_subtract(lvect1, lvect2)
|
||||
if not lvect1 or not lvect2 then return end
|
||||
|
||||
local lvect3 = {}
|
||||
for i, v in ipairs(lvect1) do
|
||||
lvect3[#lvect3 + 1] = vector.subtract(v, lvect2[i])
|
||||
end
|
||||
return lvect3
|
||||
end
|
||||
|
||||
-- yaw in radiant
|
||||
local function rotate(v, yaw)
|
||||
local sinyaw = math.sin(yaw)
|
||||
@ -61,7 +41,6 @@ local function set_node(item)
|
||||
local dest_pos = item.dest_pos
|
||||
local name = item.name or "air"
|
||||
local param2 = item.param2 or 0
|
||||
local metadata = item.metadata or {}
|
||||
local nvm = techage.get_nvm(item.base_pos)
|
||||
local node = techage.get_node_lvm(dest_pos)
|
||||
local ndef1 = minetest.registered_nodes[name]
|
||||
@ -100,7 +79,7 @@ local function push(item)
|
||||
queue[last] = item
|
||||
end
|
||||
|
||||
local function pop(nvm, time)
|
||||
local function pop()
|
||||
if first > last then return end
|
||||
local item = queue[first]
|
||||
queue[first] = nil -- to allow garbage collection
|
||||
@ -408,6 +387,9 @@ local function entity_to_node(pos, obj)
|
||||
end
|
||||
end
|
||||
|
||||
-- Create a node entitiy.
|
||||
-- * base_pos is controller block related
|
||||
-- * start_pos and dest_pos are entity positions
|
||||
local function node_to_entity(base_pos, start_pos, dest_pos)
|
||||
local meta = M(start_pos)
|
||||
local node, metadata
|
||||
@ -464,9 +446,9 @@ local function determine_dir(pos1, pos2)
|
||||
return {x=0, y=0, z=0}
|
||||
end
|
||||
|
||||
local function move_entity(obj, dest_pos, dir, is_corner)
|
||||
local function move_entity(obj, next_pos, dir, is_corner)
|
||||
local self = obj:get_luaentity()
|
||||
self.dest_pos = dest_pos
|
||||
self.next_pos = next_pos
|
||||
self.dir = dir
|
||||
if is_corner then
|
||||
local vel = vector.multiply(dir, math.min(CORNER_SPEED, self.max_speed))
|
||||
@ -477,7 +459,7 @@ local function move_entity(obj, dest_pos, dir, is_corner)
|
||||
end
|
||||
|
||||
local function moveon_entity(obj, self, pos1)
|
||||
local pos2 = next_path_pos(pos1, self.lpath, self.path_idx)
|
||||
local pos2 = next_path_pos(pos1, self.lmove, self.path_idx)
|
||||
if pos2 then
|
||||
self.path_idx = self.path_idx + 1
|
||||
local dir = determine_dir(pos1, pos2)
|
||||
@ -486,43 +468,6 @@ local function moveon_entity(obj, self, pos1)
|
||||
end
|
||||
end
|
||||
|
||||
-- Handover the entity to the next movecontroller
|
||||
local function handover_to(obj, self, pos1)
|
||||
if self.handover then
|
||||
local info = techage.get_node_info(self.handover)
|
||||
if info and info.name == "techage:ta4_movecontroller" then
|
||||
local meta = M(info.pos)
|
||||
if self.move2to1 then
|
||||
self.handover = meta:contains("handoverA") and meta:get_string("handoverA") or nil
|
||||
else
|
||||
self.handover = meta:contains("handoverB") and meta:get_string("handoverB") or nil
|
||||
end
|
||||
|
||||
self.lpath = flylib.to_path(meta:get_string("path"))
|
||||
if pos1 and self.lpath then
|
||||
self.path_idx = 2
|
||||
if self.move2to1 then
|
||||
self.lpath[1] = vector.multiply(self.lpath[1], - 1)
|
||||
end
|
||||
local pos2 = next_path_pos(pos1, self.lpath, 1)
|
||||
local dir = determine_dir(pos1, pos2)
|
||||
if not self.handover then
|
||||
local nvm = techage.get_nvm(info.pos)
|
||||
nvm.lpos1 = nvm.lpos1 or {}
|
||||
if self.move2to1 then
|
||||
nvm.lpos1[self.pos1_idx] = pos2
|
||||
|
||||
else
|
||||
nvm.lpos1[self.pos1_idx] = pos1
|
||||
end
|
||||
end
|
||||
move_entity(obj, pos2, dir)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_entity("techage:move_item", {
|
||||
initial_properties = {
|
||||
pointable = true,
|
||||
@ -538,62 +483,47 @@ minetest.register_entity("techage:move_item", {
|
||||
|
||||
on_step = function(self, dtime, moveresult)
|
||||
local stop_obj = function(obj, self)
|
||||
local dest_pos = self.dest_pos
|
||||
obj:move_to(self.dest_pos, true)
|
||||
local next_pos = self.next_pos
|
||||
obj:move_to(self.next_pos, true)
|
||||
obj:set_acceleration({x=0, y=0, z=0})
|
||||
obj:set_velocity({x=0, y=0, z=0})
|
||||
self.dest_pos = nil
|
||||
self.next_pos = nil
|
||||
self.old_dist = nil
|
||||
return dest_pos
|
||||
return next_pos
|
||||
end
|
||||
|
||||
if self.dest_pos then
|
||||
if self.next_pos then
|
||||
local obj = self.object
|
||||
local pos = obj:get_pos()
|
||||
local dist = vector.distance(pos, self.dest_pos)
|
||||
local dist = vector.distance(pos, self.next_pos)
|
||||
local speed = calc_speed(obj:get_velocity())
|
||||
self.old_dist = self.old_dist or dist
|
||||
|
||||
-- Landing
|
||||
if self.lpath and self.lpath[self.path_idx] then
|
||||
if self.lmove and self.lmove[self.path_idx] then
|
||||
if dist < 1 or dist > self.old_dist then
|
||||
local dest_pos = stop_obj(obj, self)
|
||||
if not moveon_entity(obj, self, dest_pos) then
|
||||
minetest.after(0.5, entity_to_node, dest_pos, obj)
|
||||
-- change of direction
|
||||
local next_pos = stop_obj(obj, self)
|
||||
if not moveon_entity(obj, self, next_pos) then
|
||||
minetest.after(0.5, entity_to_node, next_pos, obj)
|
||||
end
|
||||
return
|
||||
end
|
||||
elseif self.handover and dist < 0.2 or dist > self.old_dist then
|
||||
local dest_pos = stop_obj(obj, self)
|
||||
if not handover_to(obj, self, dest_pos) then
|
||||
minetest.after(0.5, entity_to_node, dest_pos, obj)
|
||||
end
|
||||
elseif dist < 0.05 or dist > self.old_dist then
|
||||
-- Landing
|
||||
local next_pos = stop_obj(obj, self)
|
||||
local dest_pos = self.item.dest_pos or next_pos
|
||||
minetest.after(0.5, entity_to_node, dest_pos, obj)
|
||||
return
|
||||
else
|
||||
if dist < 0.05 or dist > self.old_dist then
|
||||
local dest_pos = stop_obj(obj, self)
|
||||
minetest.after(0.5, entity_to_node, dest_pos, obj)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self.old_dist = dist
|
||||
|
||||
-- Braking or limit max speed
|
||||
if self.handover then
|
||||
if speed > (dist * 4) or speed > self.max_speed then
|
||||
speed = math.min(speed, math.max(dist * 4, MIN_SPEED))
|
||||
local vel = vector.multiply(self.dir,speed)
|
||||
obj:set_velocity(vel)
|
||||
obj:set_acceleration({x=0, y=0, z=0})
|
||||
end
|
||||
else
|
||||
if speed > (dist * 2) or speed > self.max_speed then
|
||||
speed = math.min(speed, math.max(dist * 2, MIN_SPEED))
|
||||
local vel = vector.multiply(self.dir,speed)
|
||||
obj:set_velocity(vel)
|
||||
obj:set_acceleration({x=0, y=0, z=0})
|
||||
end
|
||||
if speed > (dist * 2) or speed > self.max_speed then
|
||||
speed = math.min(speed, math.max(dist * 2, MIN_SPEED))
|
||||
local vel = vector.multiply(self.dir,speed)
|
||||
obj:set_velocity(vel)
|
||||
obj:set_acceleration({x=0, y=0, z=0})
|
||||
end
|
||||
|
||||
monitoring_trigger_entity(self.item)
|
||||
@ -618,30 +548,34 @@ local function is_simple_node(pos)
|
||||
return not techage.is_air_like(node.name) and techage.can_dig_node(node.name, ndef)
|
||||
end
|
||||
|
||||
local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, move2to1, handover, cpos)
|
||||
local pos2 = next_path_pos(start_pos, lpath, 1)
|
||||
-- Move node from 'pos1' to the destination, calculated by means of 'lmove'
|
||||
-- * pos and meta are controller block related
|
||||
-- * lmove is the movement as a list of `moves`
|
||||
-- * height is move block height as value between 0 and 1 and used to calculate the offset
|
||||
-- for the attached object (player).
|
||||
local function move_node(pos, meta, pos1, lmove, max_speed, height)
|
||||
local pos2 = next_path_pos(pos1, lmove, 1)
|
||||
local offs = dest_offset(lmove)
|
||||
local dest_pos = vector.add(pos1, offs)
|
||||
-- optional for non-player objects
|
||||
local yoffs = M(pos):get_float("offset")
|
||||
local yoffs = meta:get_float("offset")
|
||||
|
||||
if pos2 then
|
||||
local dir = determine_dir(start_pos, pos2)
|
||||
local obj = node_to_entity(pos, start_pos, pos2)
|
||||
local dir = determine_dir(pos1, pos2)
|
||||
local obj = node_to_entity(pos, pos1, dest_pos)
|
||||
|
||||
if obj then
|
||||
local offs = {x=0, y=height or 1, z=0}
|
||||
attach_objects(start_pos, offs, obj, yoffs)
|
||||
attach_objects(pos1, offs, obj, yoffs)
|
||||
if dir.y == 0 then
|
||||
if (dir.x ~= 0 and dir.z == 0) or (dir.x == 0 and dir.z ~= 0) then
|
||||
attach_objects(start_pos, dir, obj, yoffs)
|
||||
attach_objects(pos1, dir, obj, yoffs)
|
||||
end
|
||||
end
|
||||
local self = obj:get_luaentity()
|
||||
self.path_idx = 2
|
||||
self.pos1_idx = pos1_idx
|
||||
self.lpath = lpath
|
||||
self.lmove = lmove
|
||||
self.max_speed = max_speed
|
||||
self.move2to1 = move2to1
|
||||
self.handover = handover
|
||||
self.yoffs = yoffs
|
||||
move_entity(obj, pos2, dir)
|
||||
return true
|
||||
@ -651,14 +585,20 @@ local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, mov
|
||||
end
|
||||
end
|
||||
|
||||
local function move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, handover)
|
||||
-- Move the nodes from nvm.lpos1 to nvm.lpos2
|
||||
-- * nvm.lpos1 is a list of nodes
|
||||
-- * lmove is the movement as a list of `moves`
|
||||
-- * pos, meta, and nvm are controller block related
|
||||
--- height is move block height as value between 0 and 1 and used to calculate the offset
|
||||
-- for the attached object (player).
|
||||
local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2to1)
|
||||
local owner = meta:get_string("owner")
|
||||
techage.counting_add(owner, #lpath, #nvm.lpos1 * #lpath)
|
||||
techage.counting_add(owner, #lmove, #nvm.lpos1 * #lmove)
|
||||
|
||||
for idx = 1, #nvm.lpos1 do
|
||||
local pos1 = nvm.lpos1[idx]
|
||||
local pos2 = nvm.lpos2[idx]
|
||||
--print("move_nodes", idx, P2S(pos1), P2S(pos2))
|
||||
--print("multi_move_nodes", idx, P2S(pos1), P2S(pos2))
|
||||
|
||||
if move2to1 then
|
||||
pos1, pos2 = pos2, pos1
|
||||
@ -666,7 +606,7 @@ local function move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, ha
|
||||
|
||||
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
|
||||
if is_simple_node(pos1) and is_valid_dest(pos2) then
|
||||
if move_node(pos, idx, pos1, lpath, max_speed, height, move2to1, handover) == false then
|
||||
if move_node(pos, meta, pos1, lmove, max_speed, height) == false then
|
||||
meta:set_string("status", S("No valid node at the start position"))
|
||||
return false
|
||||
end
|
||||
@ -691,21 +631,27 @@ local function move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, ha
|
||||
return true
|
||||
end
|
||||
|
||||
-- Move nodes from lpos1 by the given x/y/z 'line'
|
||||
local function move_nodes2(pos, meta, lpos1, line, max_speed, height)
|
||||
-- Move the nodes from lpos1 to lpos2.
|
||||
-- * lpos1 is a list of nodes
|
||||
-- * lpos2 = lpos1 + move
|
||||
-- * pos and meta are controller block related
|
||||
-- * height is move block height as value between 0 and 1 and used to calculate the offset
|
||||
-- for the attached object (player).
|
||||
local function move_nodes(pos, meta, lpos1, move, max_speed, height)
|
||||
local owner = meta:get_string("owner")
|
||||
lpos1 = lpos1 or {}
|
||||
techage.counting_add(owner, #lpos1)
|
||||
|
||||
local lpos2 = {}
|
||||
for idx = 1, #lpos1 do
|
||||
|
||||
local pos1 = lpos1[idx]
|
||||
local pos2 = vector.add(lpos1[idx], line)
|
||||
local pos2 = vector.add(lpos1[idx], move)
|
||||
lpos2[idx] = pos2
|
||||
|
||||
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
|
||||
if is_simple_node(pos1) and is_valid_dest(pos2) then
|
||||
move_node(pos, idx, pos1, {line}, max_speed, height, false, false)
|
||||
move_node(pos, meta, pos1, {move}, max_speed, height)
|
||||
else
|
||||
if not is_simple_node(pos1) then
|
||||
meta:set_string("status", S("No valid node at the start position"))
|
||||
@ -728,13 +674,14 @@ local function move_nodes2(pos, meta, lpos1, line, max_speed, height)
|
||||
return true, lpos2
|
||||
end
|
||||
|
||||
-- move2to1 is the direction and is true for 'from pos2 to pos1'
|
||||
-- Move path and other data is stored as meta data of pos
|
||||
function flylib.move_to_other_pos(pos, move2to1)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local lpath, err = flylib.to_path(meta:get_string("path")) or {}
|
||||
local lmove, err = flylib.to_path(meta:get_string("path")) or {}
|
||||
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
|
||||
local height = meta:contains("height") and meta:get_float("height") or 1
|
||||
local handover
|
||||
|
||||
if err or nvm.running then return false end
|
||||
|
||||
@ -742,33 +689,28 @@ function flylib.move_to_other_pos(pos, move2to1)
|
||||
max_speed = techage.in_range(max_speed, MIN_SPEED, MAX_SPEED)
|
||||
nvm.lpos1 = nvm.lpos1 or {}
|
||||
|
||||
local offs = dest_offset(lpath)
|
||||
local offs = dest_offset(lmove)
|
||||
if move2to1 then
|
||||
lpath = reverse_path(lpath)
|
||||
lmove = reverse_path(lmove)
|
||||
end
|
||||
-- calc destination positions
|
||||
nvm.lpos2 = lvect_add_vec(nvm.lpos1, offs)
|
||||
|
||||
if move2to1 then
|
||||
handover = meta:contains("handoverA") and meta:get_string("handoverA") or nil
|
||||
else
|
||||
handover = meta:contains("handoverB") and meta:get_string("handoverB") or nil
|
||||
end
|
||||
nvm.running = move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, handover)
|
||||
nvm.running = multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2to1)
|
||||
nvm.moveBA = nvm.running and not move2to1
|
||||
return nvm.running
|
||||
end
|
||||
|
||||
function flylib.move_to(pos, line)
|
||||
-- `move` the movement as a vector
|
||||
function flylib.move_to(pos, move)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1)
|
||||
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
|
||||
local resp
|
||||
|
||||
if nvm.running then return false end
|
||||
|
||||
nvm.running, nvm.lastpos = move_nodes2(pos, meta, nvm.lastpos or nvm.lpos1, line, max_speed, height)
|
||||
nvm.running, nvm.lastpos = move_nodes(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height)
|
||||
return nvm.running
|
||||
end
|
||||
|
||||
@ -782,27 +724,28 @@ function flylib.reset_move(pos)
|
||||
|
||||
if nvm.lpos1 and nvm.lpos1[1] then
|
||||
local move = vector.subtract(nvm.lpos1[1], (nvm.lastpos or nvm.lpos1)[1])
|
||||
local resp
|
||||
|
||||
nvm.running, nvm.lastpos = move_nodes2(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height)
|
||||
nvm.running, nvm.lastpos = move_nodes(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height)
|
||||
return nvm.running
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- pos is the controller block pos
|
||||
-- lpos is a list of node positions to be moved
|
||||
-- rot is one of "l", "r", "2l", "2r"
|
||||
-- cpos is the center pos (optional)
|
||||
function flylib.rotate_nodes(pos, posses1, rot)
|
||||
function flylib.rotate_nodes(pos, lpos, rot)
|
||||
local meta = M(pos)
|
||||
local owner = meta:get_string("owner")
|
||||
-- cpos is the center pos
|
||||
local cpos = meta:contains("center") and flylib.to_vector(meta:get_string("center"))
|
||||
local posses2 = techage.rotate_around_center(posses1, rot, cpos)
|
||||
local lpos2 = techage.rotate_around_center(lpos, rot, cpos)
|
||||
local param2
|
||||
local nodes2 = {}
|
||||
|
||||
techage.counting_add(owner, #posses1 * 2)
|
||||
techage.counting_add(owner, #lpos * 2)
|
||||
|
||||
for i, pos1 in ipairs(posses1) do
|
||||
for i, pos1 in ipairs(lpos) do
|
||||
local node = techage.get_node_lvm(pos1)
|
||||
if rot == "l" then
|
||||
param2 = techage.param2_turn_right(node.param2)
|
||||
@ -813,7 +756,7 @@ function flylib.rotate_nodes(pos, posses1, rot)
|
||||
end
|
||||
if not minetest.is_protected(pos1, owner) and is_simple_node(pos1) then
|
||||
minetest.remove_node(pos1)
|
||||
nodes2[#nodes2 + 1] = {pos = posses2[i], name = node.name, param2 = param2}
|
||||
nodes2[#nodes2 + 1] = {pos = lpos2[i], name = node.name, param2 = param2}
|
||||
end
|
||||
end
|
||||
for _,item in ipairs(nodes2) do
|
||||
@ -821,7 +764,7 @@ function flylib.rotate_nodes(pos, posses1, rot)
|
||||
minetest.add_node(item.pos, {name = item.name, param2 = item.param2})
|
||||
end
|
||||
end
|
||||
return posses2
|
||||
return lpos2
|
||||
end
|
||||
|
||||
function flylib.exchange_node(pos, name, param2)
|
||||
|
@ -3,7 +3,7 @@
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019-2022 Joachim Stolberg
|
||||
Copyright (C) 2019-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
@ -520,6 +520,20 @@ function NodeStates:on_beduino_request_data(pos, topic, payload)
|
||||
end
|
||||
end
|
||||
|
||||
function NodeStates.get_beduino_state(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if node.name == "ignore" then -- unloaded node?
|
||||
return 0, {techage.UNLOADED}
|
||||
elseif nvm.techage_state == RUNNING then
|
||||
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
|
||||
if ttl < minetest.get_gametime() then
|
||||
return 0, {techage.INACTIVE}
|
||||
end
|
||||
end
|
||||
return 0, {nvm.techage_state or STOPPED}
|
||||
end
|
||||
|
||||
-- restart timer
|
||||
function NodeStates:on_node_load(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
|
@ -55,6 +55,6 @@ minetest.register_on_mods_loaded(function()
|
||||
beduino.lib.register_SystemHandler(0x140, ta_kv_init)
|
||||
beduino.lib.register_SystemHandler(0x141, ta_kv_add)
|
||||
beduino.lib.register_SystemHandler(0x142, ta_kv_get)
|
||||
vm16.register_ro_file("beduino", "ta_kvstore.c", kvstore_c)
|
||||
vm16.register_ro_file("beduino", "lib/ta_kvstore.c", kvstore_c)
|
||||
end
|
||||
end)
|
||||
|
@ -30,7 +30,7 @@ local TOTAL_MAX = INV_SIZE * FUEL_STACK_MAX
|
||||
|
||||
local function count_coal(metadata)
|
||||
local total = 0
|
||||
for _,stack in pairs(metadata.inventory.fuel) do
|
||||
for _,stack in pairs(metadata.inventory.fuel or {}) do
|
||||
total = total + stack:get_count()
|
||||
end
|
||||
return total
|
||||
|
@ -115,7 +115,7 @@ techage.Items = {
|
||||
ta3_sequencer = "techage:ta3_sequencer",
|
||||
ta3_timer = "techage:ta3_timer",
|
||||
ta3_terminal = "techage:terminal2",
|
||||
ta3_signallamp = "techage:signal_lamp_off",
|
||||
ta3_colorlamp = "techage:color_lamp_off",
|
||||
ta3_doorblock = "techage:doorblock20",
|
||||
ta3_programmer = "techage:programmer",
|
||||
ta3_doorcontroller = "techage:ta3_doorcontroller",
|
||||
|
@ -113,7 +113,7 @@ techage.manual_DE.aTitel = {
|
||||
"3,TA3 Sequenzer / Sequencer",
|
||||
"3,TA3 Timer",
|
||||
"3,TA3 Terminal",
|
||||
"3,TechAge Signallampe / Signal Lamp",
|
||||
"3,TechAge Farblampe / Color Lamp",
|
||||
"3,Tür/Tor Blöcke / Door/Gate Blocks",
|
||||
"3,TA3 Tür Controller / Door Controller",
|
||||
"3,TA3 Tür Controller II / Door Controller II",
|
||||
@ -1133,7 +1133,7 @@ techage.manual_DE.aText = {
|
||||
"\n"..
|
||||
"\n"..
|
||||
"\n",
|
||||
"Die Signallampe kann mit 'on'/'off' Kommando ein- bzw. ausgeschaltet werden. Diese Lampe braucht keinen Strom und\n"..
|
||||
"Die Farblampe kann mit 'on'/'off' Kommando ein- bzw. ausgeschaltet werden. Diese Lampe braucht keinen Strom und\n"..
|
||||
"kann mit der Spritzpistole aus der Mod \"Unified Dyes\" und über Lua/Beduino Kommandos eingefärbt werden.\n"..
|
||||
"\n"..
|
||||
"Mit dem Chat-Kommando '/ta_color' wird die Farbpalette mit den Werten für die Lua/Beduino Kommandos angezeigt und mit '/ta_send color <num>' kann die Farbe geändert werden.\n"..
|
||||
@ -2282,7 +2282,7 @@ techage.manual_DE.aItemName = {
|
||||
"ta3_sequencer",
|
||||
"ta3_timer",
|
||||
"ta3_terminal",
|
||||
"ta3_signallamp",
|
||||
"ta3_colorlamp",
|
||||
"ta3_doorblock",
|
||||
"ta3_doorcontroller",
|
||||
"ta3_doorcontroller",
|
||||
|
@ -113,7 +113,7 @@ techage.manual_EN.aTitel = {
|
||||
"3,TA3 Sequencer",
|
||||
"3,TA3 Timer",
|
||||
"3,TA3 Terminal",
|
||||
"3,TechAge Signal Lamp",
|
||||
"3,TechAge Color Lamp",
|
||||
"3,Door/Gate Blocks",
|
||||
"3,TA3 Door Controller",
|
||||
"3,TA3 Door Controller II",
|
||||
@ -2286,7 +2286,7 @@ techage.manual_EN.aItemName = {
|
||||
"ta3_sequencer",
|
||||
"ta3_timer",
|
||||
"ta3_terminal",
|
||||
"ta3_signallamp",
|
||||
"ta3_colorlamp",
|
||||
"ta3_doorblock",
|
||||
"ta3_doorcontroller",
|
||||
"ta3_doorcontroller",
|
||||
|
@ -217,7 +217,6 @@ minetest.register_node("techage:ta5_fr_controller_pas", {
|
||||
on_timer = node_timer,
|
||||
after_dig_node = after_dig_node,
|
||||
on_receive_fields = on_receive_fields,
|
||||
drawtype = "nodebox",
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
@ -257,7 +256,6 @@ minetest.register_node("techage:ta5_fr_controller_act", {
|
||||
on_timer = node_timer,
|
||||
after_dig_node = after_dig_node,
|
||||
on_receive_fields = on_receive_fields,
|
||||
drawtype = "nodebox",
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
drop = "",
|
||||
|
@ -54,7 +54,6 @@ minetest.register_node("techage:ta5_magnet1", {
|
||||
Cable:after_dig_node(pos)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
drawtype = "nodebox",
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
@ -88,7 +87,6 @@ minetest.register_node("techage:ta5_magnet2", {
|
||||
Cable:after_dig_node(pos)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
drawtype = "nodebox",
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
|
@ -3,7 +3,7 @@
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019-2022 Joachim Stolberg
|
||||
Copyright (C) 2019-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
@ -13,7 +13,7 @@
|
||||
techage = {}
|
||||
|
||||
-- Version for compatibility checks, see readme.md/history
|
||||
techage.version = 1.08
|
||||
techage.version = 1.10
|
||||
|
||||
if minetest.global_exists("tubelib") then
|
||||
minetest.log("error", "[techage] Techage can't be used together with the mod tubelib!")
|
||||
@ -27,8 +27,8 @@ elseif minetest.global_exists("techpack") then
|
||||
elseif minetest.global_exists("tubelib2") and tubelib2.version < 2.2 then
|
||||
minetest.log("error", "[techage] Techage requires tubelib2 version 2.2 or newer!")
|
||||
return
|
||||
elseif minetest.global_exists("minecart") and minecart.version < 1.08 then
|
||||
minetest.log("error", "[techage] Techage requires minecart version 1.08 or newer!")
|
||||
elseif minetest.global_exists("minecart") and minecart.version < 2.03 then
|
||||
minetest.log("error", "[techage] Techage requires minecart version 2.03 or newer!")
|
||||
return
|
||||
elseif minetest.global_exists("lcdlib") and lcdlib.version < 1.01 then
|
||||
minetest.log("error", "[techage] Techage requires lcdlib version 1.01 or newer!")
|
||||
|
@ -43,6 +43,13 @@ else
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
-- Needs to be a techage recipe, not to overwrite the clay/bakedclay recipe
|
||||
techage.furnace.register_recipe({
|
||||
output = "techage:cement_block",
|
||||
recipe = {
|
||||
"default:clay",
|
||||
},
|
||||
})
|
||||
techage.add_grinder_recipe({input="techage:cement_block", output="techage:cement_powder"})
|
||||
techage.add_grinder_recipe({input="bakedclay:white", output="techage:cement_powder"})
|
||||
end
|
||||
|
@ -30,16 +30,16 @@ if minetest.global_exists("mesecon") then
|
||||
},
|
||||
time = 6,
|
||||
})
|
||||
else
|
||||
techage.furnace.register_recipe({
|
||||
output = "techage:ta4_silicon_wafer 16",
|
||||
recipe = {
|
||||
"basic_materials:silicon",
|
||||
"basic_materials:silicon",
|
||||
"basic_materials:silicon",
|
||||
"techage:baborium_ingot"
|
||||
},
|
||||
time = 6,
|
||||
})
|
||||
end
|
||||
techage.furnace.register_recipe({
|
||||
output = "techage:ta4_silicon_wafer 16",
|
||||
recipe = {
|
||||
"basic_materials:silicon",
|
||||
"basic_materials:silicon",
|
||||
"basic_materials:silicon",
|
||||
"techage:baborium_ingot"
|
||||
},
|
||||
time = 6,
|
||||
})
|
||||
|
||||
|
||||
|
@ -171,11 +171,26 @@ minetest.register_craft({
|
||||
},
|
||||
})
|
||||
|
||||
local function contains(table, element)
|
||||
for _, value in pairs(table) do
|
||||
if value == element then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function techage.register_flower(name)
|
||||
if contains(Flowers, name) then
|
||||
return
|
||||
end
|
||||
Flowers[#Flowers+1] = name
|
||||
end
|
||||
|
||||
function techage.register_plant(name)
|
||||
if contains(Plants, name) then
|
||||
return
|
||||
end
|
||||
Plants[name] = true
|
||||
end
|
||||
|
||||
@ -201,4 +216,5 @@ minetest.after(1, function()
|
||||
end
|
||||
end
|
||||
end
|
||||
-- print(dump(Flowers))
|
||||
end)
|
||||
|
@ -343,7 +343,7 @@ techage.register_node({"techage:t4_pump", "techage:t4_pump_on"}, {
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
if topic == 69 and payload then -- Set pump limit
|
||||
if (topic == 69 or topic == 21) and payload then -- Set pump limit
|
||||
local nvm = techage.get_nvm(pos)
|
||||
State4:stop(pos, nvm)
|
||||
if payload[1] > 0 then
|
||||
|
@ -3,7 +3,7 @@
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2020 Joachim Stolberg
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
@ -394,11 +394,16 @@ minetest.register_craft({
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_button_off", "techage:ta3_button_on"}, {})
|
||||
|
||||
techage.register_node({
|
||||
"techage:ta4_button_off", "techage:ta4_button_on",
|
||||
}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "name" then
|
||||
if topic == "state" then
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
return name == "techage:ta4_button_on" and "on" or "off"
|
||||
elseif topic == "name" then
|
||||
local mem = techage.get_mem(pos)
|
||||
return mem.clicker or ""
|
||||
elseif topic == "time" then
|
||||
@ -409,7 +414,10 @@ techage.register_node({
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 144 then -- Player Name
|
||||
if topic == 131 then -- State
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
return 0, name == "techage:ta4_button_on" and {1} or {0}
|
||||
elseif topic == 144 then -- Player Name
|
||||
local mem = techage.get_mem(pos)
|
||||
return 0, mem.clicker
|
||||
elseif topic == 149 then --time
|
||||
|
@ -244,6 +244,8 @@ minetest.register_node("techage:ta4_button_2x", {
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_button_2x"}, {})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_2x",
|
||||
recipe = {
|
||||
@ -252,3 +254,12 @@ minetest.register_craft({
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_off 2",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "techage:ta4_button_2x", ""},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
@ -300,6 +300,8 @@ minetest.register_node("techage:ta4_button_4x", {
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_button_4x"}, {})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_4x",
|
||||
recipe = {
|
||||
@ -308,3 +310,12 @@ minetest.register_craft({
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_off 4",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "techage:ta4_button_4x", ""},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
@ -3,7 +3,7 @@
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
@ -21,7 +21,7 @@ local logic = techage.logic
|
||||
local BLOCKING_TIME = 8 -- seconds
|
||||
local ON_TIME = 1
|
||||
|
||||
local WRENCH_MENU = {
|
||||
local WRENCH_MENU3 = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "1,2,4,6,8,12,16",
|
||||
@ -47,6 +47,46 @@ local WRENCH_MENU = {
|
||||
}
|
||||
}
|
||||
|
||||
local WRENCH_MENU4 = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "1,2,4,6,8,12,16",
|
||||
name = "ontime",
|
||||
label = S("On Time") .. " [s]",
|
||||
tooltip = S("The time between the 'on' and 'off' commands."),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "2,4,6,8,12,16,20",
|
||||
name = "blockingtime",
|
||||
label = S("Blocking Time") .. " [s]",
|
||||
tooltip = S("The time after the 'off' command\nuntil the next 'on' command is accepted."),
|
||||
default = "8",
|
||||
},
|
||||
{
|
||||
type = "number",
|
||||
name = "countdown",
|
||||
label = S("Countdown"),
|
||||
tooltip = S("Counts down the number of items passed through\nand only triggers an 'on' command when it reaches zero."),
|
||||
default = "0",
|
||||
},
|
||||
{
|
||||
type = "output",
|
||||
name = "countdown",
|
||||
label = S("Current countdown"),
|
||||
tooltip = S("Current countdown value."),
|
||||
default = "0",
|
||||
},
|
||||
{
|
||||
type = "items",
|
||||
name = "config",
|
||||
label = S("Configured Items"),
|
||||
tooltip = S("Items which generate an 'on' command.\nIf empty, all passed items generate an 'on' command."),
|
||||
size = 4,
|
||||
}
|
||||
}
|
||||
|
||||
local function switch_on(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
local t = minetest.get_gametime()
|
||||
@ -122,6 +162,17 @@ local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
local function ta_after_formspec(pos, fields, playername)
|
||||
if fields.save then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local val = M(pos):get_int("countdown") or 0
|
||||
if val > 0 then
|
||||
nvm.countdown = val
|
||||
else
|
||||
nvm.countdown = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_detector_off", {
|
||||
description = S("TA3 Detector"),
|
||||
@ -139,7 +190,7 @@ minetest.register_node("techage:ta3_detector_off", {
|
||||
on_receive_fields = on_receive_fields,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
ta3_formspec = WRENCH_MENU3,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype = "light",
|
||||
@ -167,7 +218,7 @@ minetest.register_node("techage:ta3_detector_on", {
|
||||
on_rotate = screwdriver.disallow,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
ta3_formspec = WRENCH_MENU3,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
@ -192,7 +243,8 @@ minetest.register_node("techage:ta4_detector_off", {
|
||||
on_receive_fields = on_receive_fields,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
ta4_formspec = WRENCH_MENU4,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype = "light",
|
||||
@ -220,7 +272,8 @@ minetest.register_node("techage:ta4_detector_on", {
|
||||
on_rotate = screwdriver.disallow,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
ta4_formspec = WRENCH_MENU4,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
@ -268,13 +321,22 @@ techage.register_node({"techage:ta4_detector_off", "techage:ta4_detector_on"}, {
|
||||
if leftover then
|
||||
local inv = minetest.get_inventory({type = "node", pos = pos})
|
||||
if not inv or inv:is_empty("cfg") or inv:contains_item("cfg", ItemStack(stack:get_name())) then
|
||||
switch_on(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if leftover == true then
|
||||
nvm.counter = (nvm.counter or 0) + stack:get_count()
|
||||
else
|
||||
nvm.counter = (nvm.counter or 0) + stack:get_count() - leftover:get_count()
|
||||
local num_moved = stack:get_count()
|
||||
if leftover ~= true then
|
||||
num_moved = num_moved - leftover:get_count()
|
||||
end
|
||||
|
||||
if nvm.countdown and nvm.countdown > 0 then
|
||||
nvm.countdown = nvm.countdown - num_moved
|
||||
if nvm.countdown <= 0 then
|
||||
M(pos):set_int("countdown", 0)
|
||||
switch_on(pos)
|
||||
end
|
||||
elseif nvm.countdown == nil then
|
||||
switch_on(pos)
|
||||
end
|
||||
nvm.counter = (nvm.counter or 0) + num_moved
|
||||
end
|
||||
return leftover
|
||||
end
|
||||
@ -286,9 +348,15 @@ techage.register_node({"techage:ta4_detector_off", "techage:ta4_detector_on"}, {
|
||||
if topic == "count" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
return nvm.counter or 0
|
||||
elseif topic == "countdown" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.countdown = tonumber(payload) or 0
|
||||
M(pos):set_int("countdown", nvm.countdown)
|
||||
return true
|
||||
elseif topic == "reset" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.counter = 0
|
||||
nvm.countdown = nil
|
||||
return true
|
||||
else
|
||||
return "unsupported"
|
||||
@ -298,6 +366,12 @@ techage.register_node({"techage:ta4_detector_off", "techage:ta4_detector_on"}, {
|
||||
if topic == 6 then -- Detector Block Reset
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.counter = 0
|
||||
nvm.countdown = nil
|
||||
return 0
|
||||
elseif topic == 5 then -- Detector Block Countdown
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.countdown = tonumber(payload[1]) or 0
|
||||
M(pos):set_int("countdown", nvm.countdown)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
|
@ -3,7 +3,7 @@
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2022 Joachim Stolberg
|
||||
Copyright (C) 2022-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
@ -104,7 +104,6 @@ local function register_signallamp(name, description, tiles_off, tiles_on, node_
|
||||
|
||||
paramtype = "light",
|
||||
paramtype2 = "color",
|
||||
--palette = "techage_palette256.png",
|
||||
palette = COLORED and "unifieddyes_palette_extended.png" or "techage_palette256.png",
|
||||
groups = {choppy=2, cracky=1, not_in_creative_inventory=1, ud_param2_colorable = 1},
|
||||
|
||||
@ -148,7 +147,7 @@ local function register_signallamp(name, description, tiles_off, tiles_on, node_
|
||||
local node = techage.get_node_lvm(pos)
|
||||
switch_off(pos, node)
|
||||
return 0
|
||||
elseif topic == 70 then
|
||||
elseif topic == 70 or topic == 22 then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
switch_on(pos, node, nil, payload[1])
|
||||
return 0
|
||||
@ -196,8 +195,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
end)
|
||||
|
||||
|
||||
register_signallamp("techage:signal_lamp",
|
||||
S("TechAge Signal Lamp"),
|
||||
register_signallamp("techage:color_lamp",
|
||||
S("TechAge Color Lamp"),
|
||||
{"techage_signal_lamp.png^[colorize:#000000:80"},
|
||||
{"techage_signal_lamp.png"},
|
||||
{
|
||||
@ -209,8 +208,8 @@ register_signallamp("techage:signal_lamp",
|
||||
}
|
||||
)
|
||||
|
||||
register_signallamp("techage:signal_lamp2",
|
||||
S("TechAge Signal Lamp 2 "),
|
||||
register_signallamp("techage:color_lamp2",
|
||||
S("TechAge Color Lamp 2"),
|
||||
{"techage_signallamp2.png^[colorize:#000000:80"},
|
||||
{"techage_signallamp2.png"}
|
||||
)
|
||||
@ -232,3 +231,8 @@ minetest.register_craft({
|
||||
{"", "techage:vacuum_tube", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_alias("techage:signal_lamp_off", "techage:color_lamp_off")
|
||||
minetest.register_alias("techage:signal_lamp2_off", "techage:color_lamp2_off")
|
||||
minetest.register_alias("techage:signal_lamp_on", "techage:color_lamp_on")
|
||||
minetest.register_alias("techage:signal_lamp2_on", "techage:color_lamp2_on")
|
||||
|
@ -628,14 +628,14 @@ Im privaten Modus (private) kann das Terminal nur von Spielern verwendet werden,
|
||||
[ta3_terminal|image]
|
||||
|
||||
|
||||
### TechAge Signallampe / Signal Lamp
|
||||
### TechAge Farblampe / Color Lamp
|
||||
|
||||
Die Signallampe kann mit `on`/`off` Kommando ein- bzw. ausgeschaltet werden. Diese Lampe braucht keinen Strom und
|
||||
Die Farblampe kann mit `on`/`off` Kommando ein- bzw. ausgeschaltet werden. Diese Lampe braucht keinen Strom und
|
||||
kann mit der Spritzpistole aus der Mod "Unified Dyes" und über Lua/Beduino Kommandos eingefärbt werden.
|
||||
|
||||
Mit dem Chat-Kommando `/ta_color` wird die Farbpalette mit den Werten für die Lua/Beduino Kommandos angezeigt und mit `/ta_send color <num>` kann die Farbe geändert werden.
|
||||
|
||||
[ta3_signallamp|image]
|
||||
[ta3_colorlamp|image]
|
||||
|
||||
|
||||
### Tür/Tor Blöcke / Door/Gate Blocks
|
||||
|
@ -627,13 +627,13 @@ In public mode, all players can use the preconfigured keys.
|
||||
[ta3_terminal|image]
|
||||
|
||||
|
||||
### TechAge Signal Lamp
|
||||
### TechAge Color Lamp
|
||||
|
||||
The signal lamp can be switched on or off with the `on` / `off` command. This lamp does not need electricity and can be colored with the airbrush tool from the mod Unified Dyes" and via Lua/Beduino commands.
|
||||
|
||||
With the chat command `/ta_color` the color palette with the values for the Lua/Beduino commands is displayed and with `/ta_send color <num>` the color can be changed.
|
||||
|
||||
[ta3_signallamp|image]
|
||||
[ta3_colorlamp|image]
|
||||
|
||||
|
||||
### Door/Gate Blocks
|
||||
|
@ -363,6 +363,7 @@ Please note, that this is not a technical distinction, only a logical.
|
||||
| "state" | one of: "running", "stopped", "blocked", "standby", "fault", or "unloaded" | Techage machine state, used by many machines |
|
||||
| "state" | one of: "red", "amber", "green", "off" | Signal Tower state |
|
||||
| "state" | one of: "empty", "loaded", "full" | State of a chest or Sensor Chest |
|
||||
| "state" | one of: "on", "off" | State of a TA4 Button |
|
||||
| "fuel" | number | fuel value of a fuel consuming block |
|
||||
| "depth" | number | Read the current depth value of a quarry block (1..80) |
|
||||
| "load" | number | Read the load value in percent (0..100) of a tank, silo, accu, or battery block, or from the Signs Bot Box. Silo and tank return two values: The percentage value and the absolute value in units.<br /> Example: percent, absolute = $send_cmnd("223", "load") |
|
||||
@ -396,7 +397,8 @@ Please note, that this is not a technical distinction, only a logical.
|
||||
| "port" | string<br />`<color>=on/off` | Enable/disable a Distributor filter slot..<br />Example: `"yellow=on"`<br />colors: red, green, blue, yellow |
|
||||
| "config" | "\<slot> \<item list>" | Configure a Distributor filter slot, like: "red default:dirt dye:blue" |
|
||||
| "text" | text string | Text to be used for the Sensor Chest menu |
|
||||
| "reset" | nil | Reset the item counter of the TA4 Item Detector block |
|
||||
| "reset" | nil | Reset item and countdown counters of the TA4 Item Detector block |
|
||||
| "countdown" | number | Set countdown counter of the TA4 Item Detector block to the given value and<br />start countdown mode. |
|
||||
| "limit" | number | Configure a TA4 Pusher with the number of items that are allowed to be pushed ("flow limiter" mode)<br />limit = 0 turns off the "flow limiter" mode |
|
||||
| "limit" | number | Configure a TA4 Pump with the number of liquid units that are allowed to be pumped ("flow limiter" mode)<br />limit = 0 turns off the "flow limiter" mode |
|
||||
| "config" | item string | Configure the TA4 pusher.<br />Example: `wool:blue` |
|
||||
@ -417,7 +419,7 @@ Please note, that this is not a technical distinction, only a logical.
|
||||
| "stop" | nil | Stop command for the TA4 Sequencer. |
|
||||
| "gain" | volume | Set volume of the sound block (`volume` is a value between 0 and 1.0) |
|
||||
| "sound" | index | Select sound sample of the sound block |
|
||||
| "color" | \<color> | Set the color of the TechAge Signal Lamp and TechAge Signal Lamp 2 (color = 0..255) |
|
||||
| "color" | \<color> | Set the color of the TechAge Color Lamp and TechAge Color Lamp 2 (color = 0..255) |
|
||||
|
||||
### Server and Terminal Functions
|
||||
|
||||
|
@ -1,85 +0,0 @@
|
||||
# Techage/Beduino I/O Module
|
||||
|
||||
I/O modules support the following functions:
|
||||
|
||||
### event
|
||||
|
||||
Every signal that is sent to an I/O module triggers an event on the controller.
|
||||
Events can be queried using the `event()` function.
|
||||
If the function returns the value `1`, one or more signals have been received.
|
||||
Calling `event()` resets the event flag.
|
||||
|
||||
```c
|
||||
event()
|
||||
```
|
||||
|
||||
### read
|
||||
|
||||
Read a value from a remote techage block.
|
||||
|
||||
- *port* is the I/O module port number
|
||||
- *cmnd* is the command, like `IO_STATE` (see example code "ta_cmnd.c")
|
||||
|
||||
```c
|
||||
read(port, cmnd)
|
||||
```
|
||||
|
||||
### send_cmnd
|
||||
|
||||
Send a command to a techage block (see [commands](https://github.com/joe7575/beduino/blob/main/BEPs/bep-005_ta_cmnd.md)).
|
||||
|
||||
- *port* is the I/O module port number
|
||||
- *topic* is a number from the list of [Beduino commands](https://github.com/joe7575/beduino/blob/main/BEPs/bep-005_ta_cmnd.md)
|
||||
- *payload* is an array or a string with additional information, depending on the command. If no additional commands are required, "" can be used.
|
||||
|
||||
```c
|
||||
send_cmnd(port, topic, payload)
|
||||
```
|
||||
|
||||
### request_data
|
||||
|
||||
Request information from a techage block (see [commands](https://github.com/joe7575/beduino/blob/main/BEPs/bep-005_ta_cmnd.md)).
|
||||
|
||||
- *port* is the I/O module port number
|
||||
- *topic* is a number from the list of [Beduino commands](https://github.com/joe7575/beduino/blob/main/BEPs/bep-005_ta_cmnd.md)
|
||||
- *payload* is an array or a string with additional information, depending on the command. If no additional commands are required, "" can be used.
|
||||
- *resp* is an array for the response data. The array must be defined large enough to hold the response data.
|
||||
|
||||
```c
|
||||
request_data(port, topic, payload, resp)
|
||||
```
|
||||
|
||||
## Functions for TA4 Display and TA4 Display XL
|
||||
|
||||
### clear_screen
|
||||
|
||||
Clear the display.
|
||||
|
||||
- *port* is the I/O module port number
|
||||
|
||||
```c
|
||||
clear_screen(port)
|
||||
```
|
||||
|
||||
### append_line
|
||||
|
||||
Add a new line to the display.
|
||||
- *port* is the I/O module port number
|
||||
- *text* is the text for one line
|
||||
|
||||
```c
|
||||
append_line(port, text)
|
||||
```
|
||||
|
||||
|
||||
### write_line
|
||||
|
||||
Overwrite a text line with the given string.
|
||||
|
||||
- *port* is the I/O module port number
|
||||
- *row* ist the display line/row (1-5)
|
||||
- *text* is the text for one line
|
||||
|
||||
```c
|
||||
write_line(port, row, text)
|
||||
```
|
@ -5,8 +5,8 @@ The key/value store simplifies the handling/comparison of strings.
|
||||
The following example shows the use of the Key/Value Store, here to check the names from the Player Detector:
|
||||
|
||||
```c
|
||||
import "ta_kvstore.c"
|
||||
import "ta_iom.c"
|
||||
import "lib/ta_kvstore.c"
|
||||
import "lib/ta_iom.c"
|
||||
|
||||
var s[16];
|
||||
|
||||
|
@ -112,7 +112,7 @@
|
||||
- [TA3 Sequenzer / Sequencer](./manual_ta3_DE.md#ta3-sequenzer--sequencer)
|
||||
- [TA3 Timer](./manual_ta3_DE.md#ta3-timer)
|
||||
- [TA3 Terminal](./manual_ta3_DE.md#ta3-terminal)
|
||||
- [TechAge Signallampe / Signal Lamp](./manual_ta3_DE.md#techage-signallampe--signal-lamp)
|
||||
- [TechAge Farblampe / Color Lamp](./manual_ta3_DE.md#techage-farblampe--color-lamp)
|
||||
- [Tür/Tor Blöcke / Door/Gate Blocks](./manual_ta3_DE.md#türtor-blöcke--doorgate-blocks)
|
||||
- [TA3 Tür Controller / Door Controller](./manual_ta3_DE.md#ta3-tür-controller--door-controller)
|
||||
- [TA3 Tür Controller II / Door Controller II](./manual_ta3_DE.md#ta3-tür-controller-ii--door-controller-ii)
|
||||
|
@ -112,7 +112,7 @@
|
||||
- [TA3 Sequencer](./manual_ta3_EN.md#ta3-sequencer)
|
||||
- [TA3 Timer](./manual_ta3_EN.md#ta3-timer)
|
||||
- [TA3 Terminal](./manual_ta3_EN.md#ta3-terminal)
|
||||
- [TechAge Signal Lamp](./manual_ta3_EN.md#techage-signal-lamp)
|
||||
- [TechAge Color Lamp](./manual_ta3_EN.md#techage-color-lamp)
|
||||
- [Door/Gate Blocks](./manual_ta3_EN.md#doorgate-blocks)
|
||||
- [TA3 Door Controller](./manual_ta3_EN.md#ta3-door-controller)
|
||||
- [TA3 Door Controller II](./manual_ta3_EN.md#ta3-door-controller-ii)
|
||||
|
@ -3,12 +3,12 @@
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2020-2022 Joachim Stolberg
|
||||
Copyright (C) 2020-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Move Controller
|
||||
TA5 Fly Controller
|
||||
|
||||
]]--
|
||||
|
||||
@ -42,6 +42,13 @@ local WRENCH_MENU = {
|
||||
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 formspec(nvm, meta)
|
||||
@ -165,8 +172,6 @@ minetest.register_node("techage:ta5_flycontroller", {
|
||||
elseif fields.moveAB then
|
||||
meta:set_string("status", "")
|
||||
if fly.move_to_other_pos(pos, false) then
|
||||
nvm.moveBA = true
|
||||
nvm.running = true
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
local name = player:get_player_name()
|
||||
mark.stop(name)
|
||||
@ -175,8 +180,6 @@ minetest.register_node("techage:ta5_flycontroller", {
|
||||
elseif fields.moveBA then
|
||||
meta:set_string("status", "")
|
||||
if fly.move_to_other_pos(pos, true) then
|
||||
nvm.moveBA = false
|
||||
nvm.running = true
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
local name = player:get_player_name()
|
||||
mark.stop(name)
|
||||
@ -185,8 +188,6 @@ minetest.register_node("techage:ta5_flycontroller", {
|
||||
elseif fields.move then
|
||||
meta:set_string("status", "")
|
||||
if fly.move_to_other_pos(pos, nvm.moveBA) then
|
||||
nvm.moveBA = nvm.moveBA == false
|
||||
nvm.running = true
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
local name = player:get_player_name()
|
||||
mark.stop(name)
|
||||
@ -219,17 +220,11 @@ techage.register_node({"techage:ta5_flycontroller"}, {
|
||||
elseif topic == "state" then
|
||||
return nvm.running and "running" or "stopped"
|
||||
elseif topic == "a2b" then
|
||||
nvm.moveBA = true
|
||||
nvm.running = true
|
||||
return fly.move_to_other_pos(pos, false)
|
||||
elseif topic == "b2a" then
|
||||
nvm.moveBA = false
|
||||
nvm.running = true
|
||||
return fly.move_to_other_pos(pos, true)
|
||||
elseif topic == "move" then
|
||||
nvm.moveBA = nvm.moveBA == false
|
||||
nvm.running = true
|
||||
return fly.move_to_other_pos(pos, nvm.moveBA == false)
|
||||
return fly.move_to_other_pos(pos, nvm.moveBA)
|
||||
end
|
||||
return false
|
||||
end,
|
||||
@ -237,17 +232,11 @@ techage.register_node({"techage:ta5_flycontroller"}, {
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if topic == 11 then
|
||||
if payload[1] == 1 then
|
||||
nvm.moveBA = true
|
||||
nvm.running = true
|
||||
return fly.move_to_other_pos(pos, false) and 0 or 3
|
||||
elseif payload[1] == 2 then
|
||||
nvm.moveBA = false
|
||||
nvm.running = true
|
||||
return fly.move_to_other_pos(pos, true) and 0 or 3
|
||||
elseif payload[1] == 3 then
|
||||
nvm.moveBA = nvm.moveBA == false
|
||||
nvm.running = true
|
||||
return fly.move_to_other_pos(pos, nvm.moveBA == false) and 0 or 3
|
||||
return fly.move_to_other_pos(pos, nvm.moveBA) and 0 or 3
|
||||
end
|
||||
else
|
||||
return 2
|
||||
@ -260,6 +249,10 @@ techage.register_node({"techage:ta5_flycontroller"}, {
|
||||
end
|
||||
return 2, ""
|
||||
end,
|
||||
on_node_load = function(pos, node)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.running = false
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -34,22 +34,6 @@ local WRENCH_MENU = {
|
||||
tooltip = S("Maximum speed for moving blocks"),
|
||||
default = "8",
|
||||
},
|
||||
{
|
||||
type = "number",
|
||||
name = "handoverB",
|
||||
label = S("Handover to B"),
|
||||
tooltip = S("Number of the next movecontroller"),
|
||||
default = "",
|
||||
check = techage.check_number,
|
||||
},
|
||||
{
|
||||
type = "number",
|
||||
name = "handoverA",
|
||||
label = S("Handover to A"),
|
||||
tooltip = S("Number of the previous movecontroller"),
|
||||
default = "",
|
||||
check = techage.check_number,
|
||||
},
|
||||
{
|
||||
type = "float",
|
||||
name = "height",
|
||||
|
@ -116,8 +116,9 @@ techage.register_node({"techage:ta3_soundblock"}, {
|
||||
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] == 0 then
|
||||
if payload[1] == 1 then
|
||||
play_predefined_sound(pos)
|
||||
return 0
|
||||
end
|
||||
|
@ -28,6 +28,7 @@ techage.power = {}
|
||||
-- Helper function
|
||||
-------------------------------------------------------------------------------
|
||||
local function round(val)
|
||||
val = tonumber(val) or 0
|
||||
if val > 100 then
|
||||
return math.floor(val + 0.5)
|
||||
elseif val > 10 then
|
||||
|
@ -225,8 +225,8 @@ minetest.register_node("techage:tiny_generator", {
|
||||
meta:set_string("liquid_name", nvm.liquid.name)
|
||||
meta:set_int("liquid_amount", nvm.liquid.amount)
|
||||
meta:set_string("description", S("TA3 Tiny Power Generator") .. " (fuel: " ..
|
||||
tostring(nvm.liquid and nvm.liquid.amount or 0) .. "/" ..
|
||||
tostring(fuel.CAPACITY) .. ")")
|
||||
tostring(nvm.liquid and nvm.liquid.amount or 0) .. "/" ..
|
||||
tostring(fuel.CAPACITY) .. ")")
|
||||
end
|
||||
end,
|
||||
|
||||
|
@ -222,13 +222,29 @@ local function on_place(itemstack, placer, pointed_thing)
|
||||
end
|
||||
end
|
||||
|
||||
local function repair(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type == "node" then
|
||||
local pos = pointed_thing.under
|
||||
if not placer or minetest.is_protected(pos, placer:get_player_name()) then
|
||||
return
|
||||
end
|
||||
local number = techage.get_node_number(pos)
|
||||
if number and not techage.get_node_info(number) then
|
||||
techage.repair_number(pos)
|
||||
minetest.chat_send_player(placer:get_player_name(), "Node repaired!")
|
||||
itemstack:add_wear(65636/200)
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_tool("techage:repairkit", {
|
||||
description = S("TechAge Repair Kit"),
|
||||
inventory_image = "techage_repairkit.png",
|
||||
wield_image = "techage_repairkit.png^[transformR270",
|
||||
groups = {cracky=1, book=1},
|
||||
--on_use = repair,
|
||||
--on_place = repair,
|
||||
on_use = repair,
|
||||
on_place = repair,
|
||||
node_placement_prediction = "",
|
||||
stack_max = 1,
|
||||
})
|
||||
@ -254,3 +270,12 @@ minetest.register_craft({
|
||||
{"default:steel_ingot", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
--minetest.register_craft({
|
||||
-- output = "techage:repairkit",
|
||||
-- recipe = {
|
||||
-- {"", "", ""},
|
||||
-- {"", "techage:end_wrench", ""},
|
||||
-- {"", "", ""},
|
||||
-- },
|
||||
--})
|
||||
|
@ -102,3 +102,16 @@ Other files from Wikimedia Commons:
|
||||
RealBadAngel: (CC-BY-4.0)
|
||||
|
||||
* Everything else.
|
||||
|
||||
|
||||
## Sounds
|
||||
|
||||
* [`bell.ogg`](https://freesound.org/people/bennstir/sounds/81072/) by bennstir, CC 4.0
|
||||
* [`electricity.ogg`](https://freesound.org/people/Halleck/sounds/19486/) by Halleck, CC 4.0 (cut)
|
||||
* [`pageflip1.ogg`](https://freesound.org/people/themfish/sounds/45823/) by themfish, CC 4.0 (cut, slowed down)
|
||||
* `pageflip2.ogg` (derived from `pageflip1.ogg`)
|
||||
* [`trash.ogg`](https://freesound.org/people/OwlStorm/sounds/151231/) by OwlStorm, CC 0 (speed up)
|
||||
* [`trash_all.ogg`](https://freesound.org/people/abel_K/sounds/68280/) by abel_K, Sampling Plus 1.0 (speed up)
|
||||
* [`ui_click.ogg`](https://freesound.org/people/lartti/sounds/527569/) by lartti, CC 0 (cut)
|
||||
* [`ui_morning.ogg`](https://freesound.org/people/InspectorJ/sounds/439472/) by InspectorJ, CC 4.0
|
||||
* [`ui_owl.ogg`](https://freesound.org/people/manda_g/sounds/54987/) by manda_g, Sampling Plus 1.0 (cut)
|
||||
|
@ -145,50 +145,18 @@ minetest.after(0.01, function()
|
||||
end
|
||||
end
|
||||
|
||||
-- Step 1: group-indexed lookup table for items
|
||||
local spec_matcher = {}
|
||||
for _, name in ipairs(ui.items_list) do
|
||||
-- we only need to care about groups, exact items are handled separately
|
||||
for group, value in pairs(minetest.registered_items[name].groups) do
|
||||
if value and value ~= 0 then
|
||||
if not spec_matcher[group] then
|
||||
spec_matcher[group] = {}
|
||||
end
|
||||
spec_matcher[group][name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Step 1: Initialize cache for looking up groups
|
||||
unified_inventory.init_matching_cache()
|
||||
|
||||
-- Step 2: Find all matching items for the given spec (groups)
|
||||
local function get_matching_spec_items(specname)
|
||||
if specname:sub(1,6) ~= "group:" then
|
||||
return { [specname] = true }
|
||||
end
|
||||
local get_matching_spec_items = unified_inventory.get_matching_items
|
||||
|
||||
local accepted = {}
|
||||
for i, group in ipairs(specname:sub(7):split(",")) do
|
||||
if i == 1 then
|
||||
-- First step: Copy all possible item names in this group
|
||||
for name, _ in pairs(spec_matcher[group] or {}) do
|
||||
accepted[name] = true
|
||||
end
|
||||
else
|
||||
-- Perform filtering
|
||||
if spec_matcher[group] then
|
||||
for name, _ in pairs(accepted) do
|
||||
accepted[name] = spec_matcher[group][name]
|
||||
end
|
||||
else
|
||||
-- No matching items
|
||||
return {}
|
||||
end
|
||||
end
|
||||
end
|
||||
return accepted
|
||||
end
|
||||
|
||||
for _, recipes in pairs(ui.crafts_for.recipe) do
|
||||
for outputitemname, recipes in pairs(ui.crafts_for.recipe) do
|
||||
-- List of crafts that return this item string (variable "_")
|
||||
|
||||
-- Problem: The group cache must be initialized after all mods finished loading
|
||||
-- thus, invalid recipes might be indexed. Hence perform filtering with `new_recipe_list`
|
||||
local new_recipe_list = {}
|
||||
for _, recipe in ipairs(recipes) do
|
||||
local ingredient_items = {}
|
||||
for _, spec in pairs(recipe.items) do
|
||||
@ -204,7 +172,14 @@ minetest.after(0.01, function()
|
||||
end
|
||||
table.insert(ui.crafts_for.usage[name], recipe)
|
||||
end
|
||||
|
||||
if next(ingredient_items) then
|
||||
-- There's at least one known ingredient: mark as good recipe
|
||||
-- PS: What whatll be done about partially incomplete recipes?
|
||||
table.insert(new_recipe_list, recipe)
|
||||
end
|
||||
end
|
||||
ui.crafts_for.recipe[outputitemname] = new_recipe_list
|
||||
end
|
||||
|
||||
for _, callback in ipairs(ui.initialized_callbacks) do
|
||||
|
@ -10,25 +10,26 @@ local F = minetest.formspec_escape
|
||||
local ui = unified_inventory
|
||||
|
||||
ui.register_page("bags", {
|
||||
get_formspec = function(player)
|
||||
get_formspec = function(player, perplayer_formspec)
|
||||
local player_name = player:get_player_name()
|
||||
return { formspec = table.concat({
|
||||
ui.style_full.standard_inv_bg,
|
||||
ui.single_slot(0.925, 1.5),
|
||||
ui.single_slot(3.425, 1.5),
|
||||
ui.single_slot(5.925, 1.5),
|
||||
ui.single_slot(8.425, 1.5),
|
||||
"label["..ui.style_full.form_header_x..","..ui.style_full.form_header_y..";" .. F(S("Bags")) .. "]",
|
||||
"button[0.6125,2.75;1.875,0.75;bag1;" .. F(S("Bag @1", 1)) .. "]",
|
||||
"button[3.1125,2.75;1.875,0.75;bag2;" .. F(S("Bag @1", 2)) .. "]",
|
||||
"button[5.6125,2.75;1.875,0.75;bag3;" .. F(S("Bag @1", 3)) .. "]",
|
||||
"button[8.1125,2.75;1.875,0.75;bag4;" .. F(S("Bag @1", 4)) .. "]",
|
||||
local std_inv_x = perplayer_formspec.std_inv_x
|
||||
local formspec = {
|
||||
perplayer_formspec.standard_inv_bg,
|
||||
"label[", perplayer_formspec.form_header_x, ",",
|
||||
perplayer_formspec.form_header_y, ";", F(S("Bags")), "]",
|
||||
"listcolors[#00000000;#00000000]",
|
||||
"list[detached:" .. F(player_name) .. "_bags;bag1;1.075,1.65;1,1;]",
|
||||
"list[detached:" .. F(player_name) .. "_bags;bag2;3.575,1.65;1,1;]",
|
||||
"list[detached:" .. F(player_name) .. "_bags;bag3;6.075,1.65;1,1;]",
|
||||
"list[detached:" .. F(player_name) .. "_bags;bag4;8.575,1.65;1,1;]"
|
||||
}) }
|
||||
}
|
||||
|
||||
for i = 1, 4 do
|
||||
local x = std_inv_x + i * 2.5
|
||||
formspec[#formspec + 1] = ui.single_slot(x - 1.875, 1.5)
|
||||
formspec[#formspec + 1] = string.format("list[detached:%s_bags;bag%i;%.3f,1.65;1,1;]",
|
||||
F(player_name), i, x - 1.725)
|
||||
formspec[#formspec + 1] = string.format("button[%.4f,2.75;1.875,0.75;bag%i;%s]",
|
||||
x - 2.1875, i, F(S("Bag @1", i)))
|
||||
end
|
||||
|
||||
return { formspec = table.concat(formspec) }
|
||||
end,
|
||||
})
|
||||
|
||||
@ -36,7 +37,6 @@ ui.register_button("bags", {
|
||||
type = "image",
|
||||
image = "ui_bags_icon.png",
|
||||
tooltip = S("Bags"),
|
||||
hide_lite=true
|
||||
})
|
||||
|
||||
local function get_player_bag_stack(player, i)
|
||||
@ -48,23 +48,38 @@ end
|
||||
|
||||
for bag_i = 1, 4 do
|
||||
ui.register_page("bag" .. bag_i, {
|
||||
get_formspec = function(player)
|
||||
get_formspec = function(player, perplayer_formspec)
|
||||
local stack = get_player_bag_stack(player, bag_i)
|
||||
local image = stack:get_definition().inventory_image
|
||||
local slots = stack:get_definition().groups.bagslots
|
||||
local std_inv_x = perplayer_formspec.std_inv_x
|
||||
local lite_mode = perplayer_formspec.is_lite_mode
|
||||
|
||||
local bag_inv_y, header_x, header_y = 1.5, 0.3, 0.65
|
||||
if lite_mode then
|
||||
bag_inv_y = 0.5
|
||||
header_x = perplayer_formspec.form_header_x
|
||||
header_y = perplayer_formspec.form_header_y
|
||||
end
|
||||
|
||||
local formspec = {
|
||||
ui.style_full.standard_inv_bg,
|
||||
ui.make_inv_img_grid(0.3, 1.5, 8, slots/8),
|
||||
"image[9.2,0.4;1,1;" .. image .. "]",
|
||||
"label[0.3,0.65;" .. F(S("Bag @1", bag_i)) .. "]",
|
||||
perplayer_formspec.standard_inv_bg,
|
||||
ui.make_inv_img_grid(std_inv_x, bag_inv_y, 8, slots/8),
|
||||
"label[", header_x, ",", header_y, ";", F(S("Bag @1", bag_i)), "]",
|
||||
"listcolors[#00000000;#00000000]",
|
||||
"listring[current_player;main]",
|
||||
string.format("list[current_player;bag%icontents;%f,%f;8,3;]",
|
||||
bag_i, 0.3 + ui.list_img_offset, 1.5 + ui.list_img_offset),
|
||||
"listring[current_name;bag" .. bag_i .. "contents]",
|
||||
bag_i, std_inv_x + ui.list_img_offset, bag_inv_y + ui.list_img_offset),
|
||||
"listring[current_name;bag", bag_i, "contents]",
|
||||
}
|
||||
|
||||
if lite_mode then
|
||||
return { formspec = table.concat(formspec) }
|
||||
end
|
||||
|
||||
local n = #formspec + 1
|
||||
formspec[n] = "image[" .. std_inv_x + 8.9 .. ",0.4;1,1;" .. image .. "]"
|
||||
n = n + 1
|
||||
|
||||
local player_name = player:get_player_name() -- For if statement.
|
||||
if ui.trash_enabled
|
||||
|
@ -57,30 +57,47 @@ end)
|
||||
local function apply_new_filter(player, search_text, new_dir)
|
||||
local player_name = player:get_player_name()
|
||||
|
||||
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
|
||||
minetest.sound_play("ui_click", {to_player=player_name, gain = 0.1})
|
||||
ui.apply_filter(player, search_text, new_dir)
|
||||
ui.current_searchbox[player_name] = search_text
|
||||
ui.set_inventory_formspec(player, ui.current_page[player_name])
|
||||
end
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
-- Search box handling
|
||||
local function receive_fields_searchbox(player, formname, fields)
|
||||
local player_name = player:get_player_name()
|
||||
|
||||
local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name)
|
||||
-- always take new search text, even if not searching on it yet
|
||||
if fields.searchbox and fields.searchbox ~= ui.current_searchbox[player_name] then
|
||||
ui.current_searchbox[player_name] = fields.searchbox
|
||||
end
|
||||
|
||||
if fields.searchbutton
|
||||
or fields.key_enter_field == "searchbox" then
|
||||
|
||||
if ui.current_searchbox[player_name] ~= ui.activefilter[player_name] then
|
||||
ui.apply_filter(player, ui.current_searchbox[player_name], "nochange")
|
||||
ui.set_inventory_formspec(player, ui.current_page[player_name])
|
||||
minetest.sound_play("paperflip2",
|
||||
{to_player=player_name, gain = 1.0})
|
||||
end
|
||||
elseif fields.searchresetbutton then
|
||||
if ui.activefilter[player_name] ~= "" then
|
||||
apply_new_filter(player, "", "nochange")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname ~= "" then
|
||||
return
|
||||
end
|
||||
|
||||
-- always take new search text, even if not searching on it yet
|
||||
local dirty_search_filter = false
|
||||
receive_fields_searchbox(player, formname, fields)
|
||||
|
||||
if fields.searchbox
|
||||
and fields.searchbox ~= unified_inventory.current_searchbox[player_name] then
|
||||
unified_inventory.current_searchbox[player_name] = fields.searchbox
|
||||
dirty_search_filter = true
|
||||
end
|
||||
local player_name = player:get_player_name()
|
||||
|
||||
local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name)
|
||||
|
||||
local clicked_category
|
||||
for name, value in pairs(fields) do
|
||||
@ -114,7 +131,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
for i, def in pairs(unified_inventory.buttons) do
|
||||
if fields[def.name] then
|
||||
def.action(player)
|
||||
minetest.sound_play("click",
|
||||
minetest.sound_play("ui_click",
|
||||
{to_player=player_name, gain = 0.1})
|
||||
return
|
||||
end
|
||||
@ -179,7 +196,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
end
|
||||
end
|
||||
if clicked_item then
|
||||
minetest.sound_play("click",
|
||||
minetest.sound_play("ui_click",
|
||||
{to_player=player_name, gain = 0.1})
|
||||
local page = unified_inventory.current_page[player_name]
|
||||
local player_creative = unified_inventory.is_creative(player_name)
|
||||
@ -201,25 +218,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
end
|
||||
end
|
||||
|
||||
if fields.searchbutton
|
||||
or fields.key_enter_field == "searchbox" then
|
||||
if dirty_search_filter then
|
||||
ui.apply_filter(player, ui.current_searchbox[player_name], "nochange")
|
||||
ui.set_inventory_formspec(player, ui.current_page[player_name])
|
||||
minetest.sound_play("paperflip2",
|
||||
{to_player=player_name, gain = 1.0})
|
||||
end
|
||||
elseif fields.searchresetbutton then
|
||||
if ui.activefilter[player_name] ~= "" then
|
||||
apply_new_filter(player, "", "nochange")
|
||||
end
|
||||
end
|
||||
|
||||
-- alternate buttons
|
||||
if not (fields.alternate or fields.alternate_prev) then
|
||||
return
|
||||
end
|
||||
minetest.sound_play("click",
|
||||
minetest.sound_play("ui_click",
|
||||
{to_player=player_name, gain = 0.1})
|
||||
local item_name = unified_inventory.current_item[player_name]
|
||||
if not item_name then
|
||||
|
@ -24,7 +24,9 @@ Grouped by use-case, afterwards sorted alphabetically.
|
||||
Callbacks
|
||||
---------
|
||||
|
||||
Register a callback that will be run whenever a craft is registered via unified_inventory.register_craft:
|
||||
Register a callback that will be run whenever a craft is registered via unified_inventory.register_craft.
|
||||
This callback is run before any recipe ingredients checks, hence it is also executed on recipes that are
|
||||
purged after all mods finished loading.
|
||||
|
||||
unified_inventory.register_on_craft_registered(
|
||||
function (item_name, options)
|
||||
|
@ -1,4 +1,5 @@
|
||||
local S = minetest.get_translator("unified_inventory")
|
||||
local ui = unified_inventory
|
||||
|
||||
function unified_inventory.extract_groupnames(groupname)
|
||||
local specname = ItemStack(groupname):get_name()
|
||||
@ -26,6 +27,7 @@ end
|
||||
-- It may be a comma-separated list of group names. This is really a
|
||||
-- "group:..." ingredient specification, minus the "group:" prefix.
|
||||
|
||||
-- TODO Replace this with the more efficient spec matcher (below)
|
||||
local function compute_group_item(group_name_list)
|
||||
local group_names = group_name_list:split(",")
|
||||
local candidate_items = {}
|
||||
@ -84,3 +86,61 @@ function unified_inventory.get_group_item(group_name)
|
||||
return group_item_cache[group_name]
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
This is for filtering known items by groups
|
||||
e.g. find all items that match "group:flower,yellow" (flower AND yellow groups)
|
||||
]]
|
||||
local spec_matcher = {}
|
||||
function unified_inventory.init_matching_cache()
|
||||
for _, name in ipairs(ui.items_list) do
|
||||
-- we only need to care about groups, exact items are handled separately
|
||||
for group, value in pairs(minetest.registered_items[name].groups) do
|
||||
if value and value ~= 0 then
|
||||
if not spec_matcher[group] then
|
||||
spec_matcher[group] = {}
|
||||
end
|
||||
spec_matcher[group][name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Retrieves all matching items
|
||||
|
||||
Arguments:
|
||||
specname (string): Item name or group(s) to filter
|
||||
|
||||
Output:
|
||||
{
|
||||
matchingitem1 = true,
|
||||
...
|
||||
}
|
||||
]]
|
||||
function unified_inventory.get_matching_items(specname)
|
||||
if specname:sub(1,6) ~= "group:" then
|
||||
return { [specname] = true }
|
||||
end
|
||||
|
||||
local accepted = {}
|
||||
for i, group in ipairs(specname:sub(7):split(",")) do
|
||||
if i == 1 then
|
||||
-- First step: Copy all possible item names in this group
|
||||
for name, _ in pairs(spec_matcher[group] or {}) do
|
||||
accepted[name] = true
|
||||
end
|
||||
else
|
||||
-- Perform filtering
|
||||
if spec_matcher[group] then
|
||||
for name, _ in pairs(accepted) do
|
||||
accepted[name] = spec_matcher[group][name]
|
||||
end
|
||||
else
|
||||
-- No matching items
|
||||
return {}
|
||||
end
|
||||
end
|
||||
end
|
||||
return accepted
|
||||
end
|
||||
|
@ -274,9 +274,11 @@ local function formspec_add_item_browser(player, formspec, ui_peruser)
|
||||
end
|
||||
end
|
||||
end
|
||||
formspec[n] = string.format("label[%f,%f;%s: %s]",
|
||||
ui_peruser.page_buttons_x + ui_peruser.btn_spc * (ui_peruser.is_lite_mode and 1 or 2),
|
||||
ui_peruser.page_buttons_y + 0.1 + ui_peruser.btn_spc * 2,
|
||||
formspec[n] = "style[page_number;content_offset=0]"
|
||||
formspec[n + 1] = string.format("image_button[%f,%f;%f,0.4;;page_number;%s: %s;false;false;]",
|
||||
ui_peruser.page_buttons_x,
|
||||
ui_peruser.page_buttons_y + ui_peruser.btn_spc * 2 - 0.1,
|
||||
ui_peruser.btn_spc * (bn - 1) + ui_peruser.btn_size,
|
||||
F(S("Page")), S("@1 of @2",page2,pagemax))
|
||||
end
|
||||
|
||||
|
@ -126,25 +126,18 @@ Example output:
|
||||
}
|
||||
--]]
|
||||
function unified_inventory.find_usable_items(inv_items, craft_items)
|
||||
local get_group = minetest.get_item_group
|
||||
local result = {}
|
||||
|
||||
for craft_item in pairs(craft_items) do
|
||||
local group = craft_item:match("^group:(.+)")
|
||||
local found = {}
|
||||
-- may specify group:type1,type2
|
||||
local items = unified_inventory.get_matching_items(craft_item)
|
||||
|
||||
if group ~= nil then
|
||||
for inv_item in pairs(inv_items) do
|
||||
if get_group(inv_item, group) > 0 then
|
||||
found[inv_item] = true
|
||||
end
|
||||
end
|
||||
else
|
||||
if inv_items[craft_item] ~= nil then
|
||||
found[craft_item] = true
|
||||
local found = {}
|
||||
for itemname, _ in pairs(items) do
|
||||
if inv_items[itemname] then
|
||||
found[itemname] = true
|
||||
end
|
||||
end
|
||||
|
||||
result[craft_item] = found
|
||||
end
|
||||
|
||||
|
@ -98,7 +98,7 @@ ui.register_button("misc_set_day", {
|
||||
action = function(player)
|
||||
local player_name = player:get_player_name()
|
||||
if minetest.check_player_privs(player_name, {settime=true}) then
|
||||
minetest.sound_play("birds",
|
||||
minetest.sound_play("ui_morning",
|
||||
{to_player=player_name, gain = 1.0})
|
||||
minetest.set_timeofday((6000 % 24000) / 24000)
|
||||
minetest.chat_send_player(player_name,
|
||||
@ -122,7 +122,7 @@ ui.register_button("misc_set_night", {
|
||||
action = function(player)
|
||||
local player_name = player:get_player_name()
|
||||
if minetest.check_player_privs(player_name, {settime=true}) then
|
||||
minetest.sound_play("owl",
|
||||
minetest.sound_play("ui_owl",
|
||||
{to_player=player_name, gain = 1.0})
|
||||
minetest.set_timeofday((21000 % 24000) / 24000)
|
||||
minetest.chat_send_player(player_name,
|
||||
@ -183,14 +183,14 @@ ui.register_page("craft", {
|
||||
local n=#formspec+1
|
||||
|
||||
if ui.trash_enabled or ui.is_creative(player_name) or minetest.get_player_privs(player_name).give then
|
||||
formspec[n] = string.format("label[%f,%f;%s]", craftx + 6.45, crafty + 2.4, F(S("Trash:")))
|
||||
formspec[n] = string.format("label[%f,%f;%s]", craftx + 6.35, crafty + 2.3, F(S("Trash:")))
|
||||
formspec[n+1] = ui.make_trash_slot(craftx + 6.25, crafty + 2.5)
|
||||
n=n + 2
|
||||
end
|
||||
|
||||
if ui.is_creative(player_name) then
|
||||
formspec[n] = ui.single_slot(craftx - 2.5, crafty + 2.5)
|
||||
formspec[n+1] = string.format("label[%f,%f;%s]", craftx - 2.3, crafty + 2.4,F(S("Refill:")))
|
||||
formspec[n+1] = string.format("label[%f,%f;%s]", craftx - 2.4, crafty + 2.3, F(S("Refill:")))
|
||||
formspec[n+2] = string.format("list[detached:%srefill;main;%f,%f;1,1;]",
|
||||
F(player_name), craftx - 2.5 + ui.list_img_offset, crafty + 2.5 + ui.list_img_offset)
|
||||
end
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
unified_inventory/sounds/ui_click.ogg
Normal file
BIN
unified_inventory/sounds/ui_click.ogg
Normal file
Binary file not shown.
BIN
unified_inventory/sounds/ui_morning.ogg
Normal file
BIN
unified_inventory/sounds/ui_morning.ogg
Normal file
Binary file not shown.
BIN
unified_inventory/sounds/ui_owl.ogg
Normal file
BIN
unified_inventory/sounds/ui_owl.ogg
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user