first checkin

This commit is contained in:
Joachim Stolberg 2019-03-02 12:24:48 +01:00
parent 37e502737f
commit e70e638d3a
122 changed files with 4765 additions and 0 deletions

434
basis/command.lua Normal file
View File

@ -0,0 +1,434 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Basis functions for inter-node communication
]]--
--- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
------------------------------------------------------------------
-- Data base storage
-------------------------------------------------------------------
local storage = minetest.get_mod_storage()
local NextNumber = minetest.deserialize(storage:get_string("NextNumber")) or 1
local Version = minetest.deserialize(storage:get_string("Version")) or 1
local Number2Pos = minetest.deserialize(storage:get_string("Number2Pos")) or {}
local function update_mod_storage()
minetest.log("action", "[TechAge] Store data...")
storage:set_string("NextNumber", minetest.serialize(NextNumber))
storage:set_string("Version", minetest.serialize(Version))
storage:set_string("Number2Pos", minetest.serialize(Number2Pos))
storage:set_string("Key2Number", nil) -- not used any more
-- store data each hour
minetest.after(60*59, update_mod_storage)
minetest.log("action", "[TechAge] Data stored")
end
minetest.register_on_shutdown(function()
update_mod_storage()
end)
-- store data after one hour
minetest.after(60*59, update_mod_storage)
-- Key2Number will be generated at runtine
local Key2Number = {}
local Name2Name = {} -- translation table
-------------------------------------------------------------------
-- Local helper functions
-------------------------------------------------------------------
-- Localize functions to avoid table lookups (better performance).
local string_split = string.split
local NodeDef = techage.NodeDef
local Tube = techage.Tube
-- Determine position related node number for addressing purposes
local function get_number(pos)
local key = minetest.hash_node_position(pos)
if not Key2Number[key] then
Key2Number[key] = NextNumber
NextNumber = NextNumber + 1
end
return string.format("%u", Key2Number[key])
end
local function generate_Key2Number()
local key
for num,item in pairs(Number2Pos) do
key = minetest.hash_node_position(item.pos)
Key2Number[key] = num
end
end
local function not_protected(pos, placer_name, clicker_name)
local meta = minetest.get_meta(pos)
if meta then
local cached_name = meta:get_string("techage_cached_name")
if placer_name and (placer_name == cached_name or not minetest.is_protected(pos, placer_name)) then
meta:set_string("techage_cached_name", placer_name)
if clicker_name == nil or not minetest.is_protected(pos, clicker_name) then
return true
end
end
end
return false
end
local function register_lbm(name, nodenames)
minetest.register_lbm({
label = "[Tubelib] Node update",
name = name.."update",
nodenames = nodenames,
run_at_every_load = true,
action = function(pos, node)
local name = Name2Name[node.name]
if NodeDef[name] and NodeDef[name].on_node_load then
NodeDef[name].on_node_load(pos)
end
end
})
end
local DirToSide = {"B", "R", "F", "L", "D", "U"}
local function dir_to_side(dir, param2)
if dir < 5 then
dir = (((dir - 1) - (param2 % 4)) % 4) + 1
end
return DirToSide[dir]
end
local SideToDir = {B=1, R=2, F=3, L=4, D=5, U=6}
local function side_to_dir(side, param2)
local dir = SideToDir[side]
if dir < 5 then
dir = (((dir - 1) + (param2 % 4)) % 4) + 1
end
return dir
end
local function get_dest_node(pos, side)
-- TODO die Daten aus dem Cache holen und ueber die node callback wieder loeschen
local _,node = Tube:get_node(pos)
local dir = side_to_dir(side, node.param2)
local spos, sdir = Tube:get_connected_node_pos(pos, dir)
_,node = Tube:get_node(spos)
local in_side = dir_to_side(sdir, node.param2)
return spos, in_side, Name2Name[node.name] or node.name
end
local function item_handling_node(name)
local node_def = name and NodeDef[name]
if node_def then
return node_def.on_pull_item or node_def.on_push_item or node_def.is_pusher
end
end
-------------------------------------------------------------------
-- API helper functions
-------------------------------------------------------------------
-- Check the given list of numbers.
-- Returns true if number(s) is/are valid and point to real nodes.
function techage.check_numbers(numbers)
if numbers then
for _,num in ipairs(string_split(numbers, " ")) do
if Number2Pos[num] == nil then
return false
end
end
return true
end
return false
end
-- Function returns { pos, name } for the node on the given position number.
function techage.get_node_info(dest_num)
if Number2Pos[dest_num] then
return Number2Pos[dest_num]
end
return nil
end
-- Function returns the node number from the given position or
-- nil, if no node number for this position is assigned.
function techage.get_node_number(pos)
local key = minetest.hash_node_position(pos)
local num = Key2Number[key]
if num then
num = string.format("%u", num)
if Number2Pos[num] and Number2Pos[num].name then
return num
end
end
return nil
end
-- Function is used for available nodes with lost numbers, only.
function techage.get_new_number(pos, name)
-- store position
local number = get_number(pos)
Number2Pos[number] = {
pos = pos,
name = name,
}
return number
end
-------------------------------------------------------------------
-- Node construction/destruction functions
-------------------------------------------------------------------
-- Add node to the techage lists.
-- Function determines and returns the node position number,
-- needed for message communication.
function techage.add_node(pos, name)
if item_handling_node(name) then
Tube:after_place_node(pos)
end
-- store position
local number = get_number(pos)
Number2Pos[number] = {
pos = pos,
name = name,
}
return number
end
-- Function removes the node from the techage lists.
function techage.remove_node(pos)
local number = get_number(pos)
local name
if Number2Pos[number] then
name = Number2Pos[number].name
Number2Pos[number] = {
pos = pos,
name = nil,
time = minetest.get_day_count() -- used for reservation timeout
}
end
if item_handling_node(name) then
Tube:after_dig_node(pos)
end
end
-------------------------------------------------------------------
-- Node register function
-------------------------------------------------------------------
-- Register node for techage communication
-- Call this function only at load time!
-- Param name: The node name like "techage:pusher"
-- Param add_names: Alternativ node names if needded, e.g.: "techage:pusher_active"
-- Param node_definition: A table according to:
-- {
-- on_pull_item = func(pos, side, player_name, num),
-- on_push_item = func(pos, side, item, player_name),
-- on_unpull_item = func(pos, side, item, player_name),
-- on_recv_message = func(pos, topic, payload),
-- on_node_load = func(pos), -- LBM function
-- on_node_repair = func(pos), -- repair defect (feature!) nodes
-- }
function techage.register_node(name, add_names, node_definition)
NodeDef[name] = node_definition
-- store facedir table for all known node names
Name2Name[name] = name
for _,n in ipairs(add_names) do
Name2Name[n] = name
end
if node_definition.on_pull_item or node_definition.on_push_item or
node_definition.is_pusher then
Tube:add_secondary_node_names({name})
Tube:add_secondary_node_names(add_names)
techage.KnownNodes[name] = true
for _,n in ipairs(add_names) do
techage.KnownNodes[n] = true
end
end
-- register LBM
if node_definition.on_node_load then
local nodenames = {name}
for _,n in ipairs(add_names) do
nodenames[#nodenames + 1] = n
end
register_lbm(name, nodenames)
end
end
-------------------------------------------------------------------
-- Send message functions
-------------------------------------------------------------------
function techage.send_message(numbers, placer_name, clicker_name, topic, payload)
for _,num in ipairs(string_split(numbers, " ")) do
if Number2Pos[num] and Number2Pos[num].name then
local data = Number2Pos[num]
if not_protected(data.pos, placer_name, clicker_name) then
if NodeDef[data.name] and NodeDef[data.name].on_recv_message then
NodeDef[data.name].on_recv_message(data.pos, topic, payload)
end
end
end
end
end
function techage.send_request(number, topic, payload)
if Number2Pos[number] and Number2Pos[number].name then
local data = Number2Pos[number]
if NodeDef[data.name] and NodeDef[data.name].on_recv_message then
return NodeDef[data.name].on_recv_message(data.pos, topic, payload)
end
end
return false
end
-- for defect nodes
function techage.repair_node(pos)
local node = minetest.get_node(pos)
local name = Name2Name[node.name]
if NodeDef[name] and NodeDef[name].on_node_repair then
return NodeDef[name].on_node_repair(pos)
end
return false
end
-------------------------------------------------------------------
-- Client side Push/Pull item functions
-------------------------------------------------------------------
function techage.pull_items(pos, side, num)
local npos, nside, name = get_dest_node(pos, side)
if npos == nil then return end
if NodeDef[name] and NodeDef[name].on_pull_item then
return NodeDef[name].on_pull_item(npos, nside, num)
end
return nil
end
function techage.push_items(pos, side, stack)
local npos, nside, name = get_dest_node(pos, side)
if npos == nil then return end
if NodeDef[name] and NodeDef[name].on_push_item then
return NodeDef[name].on_push_item(npos, nside, stack)
elseif name == "air" then
minetest.add_item(npos, stack)
return true
end
return false
end
function techage.unpull_items(pos, side, items)
local npos, nside, name = get_dest_node(pos, side)
if npos == nil then return end
if NodeDef[name] and NodeDef[name].on_unpull_item then
return NodeDef[name].on_unpull_item(npos, nside, items)
end
return false
end
-------------------------------------------------------------------
-- Server side helper functions
-------------------------------------------------------------------
-- Get the given number of items from the inve. The position within the list
-- is random so that different item stacks will be considered.
-- Returns nil if ItemList is empty.
function techage.get_items(inv, listname, num)
if inv:is_empty(listname) then
return nil
end
local size = inv:get_size(listname)
local startpos = math.random(1, size)
for idx = startpos, startpos+size do
idx = (idx % size) + 1
local items = inv:get_stack(listname, idx)
if items:get_count() > 0 then
local taken = items:take_item(num)
inv:set_stack(listname, idx, items)
return taken
end
end
return nil
end
-- Put the given stack into the given ItemList.
-- Function returns false if ItemList is full.
function techage.put_item(inv, listname, stack)
if inv:room_for_item(listname, stack) then
inv:add_item(listname, stack)
return true
end
return false
end
-- Return "full", "loaded", or "empty" depending
-- on the inventory load.
-- Full is returned, when no empty stack is available.
function techage.get_inv_state(inv, listname)
local state
if inv:is_empty(listname) then
state = "empty"
else
local list = inv:get_list(listname)
state = "full"
for _, item in ipairs(list) do
if item:is_empty() then
return "loaded"
end
end
end
return state
end
-------------------------------------------------------------------------------
-- Data Maintenance
-------------------------------------------------------------------------------
local function data_maintenance()
minetest.log("info", "[TechAge] Data maintenance started")
-- Remove old unused positions
local Tbl = table.copy(Number2Pos)
Number2Pos = {}
local day_cnt = minetest.get_day_count()
for num,item in pairs(Tbl) do
if item.name then
Number2Pos[num] = item
-- data not older than 5 real days
elseif item.time and (item.time + (72*5)) > day_cnt then
Number2Pos[num] = item
else
minetest.log("info", "Position deleted", num)
end
end
minetest.log("info", "[TechAge] Data maintenance finished")
end
generate_Key2Number()
-- maintain data after 5 seconds
-- (minetest.get_day_count() will not be valid at start time)
minetest.after(5, data_maintenance)

45
basis/intllib.lua Normal file
View File

@ -0,0 +1,45 @@
-- Fallback functions for when `intllib` is not installed.
-- Code released under Unlicense <http://unlicense.org>.
-- Get the latest version of this file at:
-- https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua
local function format(str, ...)
local args = { ... }
local function repl(escape, open, num, close)
if escape == "" then
local replacement = tostring(args[tonumber(num)])
if open == "" then
replacement = replacement..close
end
return replacement
else
return "@"..open..num..close
end
end
return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl))
end
local gettext, ngettext
if minetest.get_modpath("intllib") then
if intllib.make_gettext_pair then
-- New method using gettext.
gettext, ngettext = intllib.make_gettext_pair()
else
-- Old method using text files.
gettext = intllib.Getter()
end
end
-- Fill in missing functions.
gettext = gettext or function(msgid, ...)
return format(msgid, ...)
end
ngettext = ngettext or function(msgid, msgid_plural, n, ...)
return format(n==1 and msgid or msgid_plural, ...)
end
return gettext, ngettext

79
basis/junction.lua Normal file
View File

@ -0,0 +1,79 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Junction for power distribution
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local function bit(p)
return 2 ^ (p - 1) -- 1-based indexing
end
-- Typical call: if hasbit(x, bit(3)) then ...
local function hasbit(x, p)
return x % (p + p) >= p
end
local function setbit(x, p)
return hasbit(x, p) and x or x + p
end
local function get_node_box(val, size, boxes)
local fixed = {{-size, -size, -size, size, size, size}}
for i = 1,6 do
if hasbit(val, bit(i)) then
for _,box in ipairs(boxes[i]) do
table.insert(fixed, box)
end
end
end
return {
type = "fixed",
fixed = fixed,
}
end
-- 'size' is the size of the junction cube without any connection, e.g. 1/8
-- 'boxes' is a table with 6 table elements for the 6 possible connection arms
-- 'network' is the tubelib2 instance
-- 'node' is the node definition with tiles, callback functions, and so on
function techage.register_junction(name, size, boxes, network, node)
for idx = 0,63 do
node.groups.techage_trowel = 1
node.groups.not_in_creative_inventory = idx
node.drawtype = "nodebox"
node.node_box = get_node_box(idx, size, boxes)
node.paramtype2 = "facedir" -- important!
node.on_rotate = screwdriver.disallow -- important!
node.paramtype = "light"
node.sunlight_propagates = true
node.is_ground_content = false
node.drop = name.."0"
minetest.register_node(name..idx, table.copy(node))
network:add_secondary_node_names({name..idx})
end
end
function techage.junction_type(conn)
local val = 0
for idx = 1,6 do
if conn[idx] then
val = setbit(val, bit(idx))
end
end
return val
end

496
basis/node_states.lua Normal file
View File

@ -0,0 +1,496 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
A state model/class for TechAge nodes.
]]--
--[[
Node states:
+-----------------------------------+ +------------+
| | | |
| V V |
| +---------+ |
| | | |
| +---------| STOPPED | |
| | | | |
| button | +---------+ |
| | ^ |
repair | V | button |
| +---------+ | | button
| | |---------+ |
| | RUNNING | |
| +--------| |---------+ |
| | +---------+ | |
| | ^ | | |
| | | | | |
| V | V V |
| +---------+ +----------+ +---------+ |
| | | | | | | |
+---| DEFECT | | STANDBY/ | | FAULT |----------+
| | | BLOCKED | | |
+---------+ +----------+ +---------+
Node metadata:
"tubelib_number" - string with tubelib number, like "123"
"tubelib_state" - node state, like "RUNNING"
"tubelib_item_meter" - node item/runtime counter
"tubelib_countdown" - countdown to stadby mode
"tubelib_aging" - aging counter
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
--
-- TechAge machine states
--
techage.STOPPED = 1 -- not operational/turned off
techage.RUNNING = 2 -- in normal operation/turned on
techage.STANDBY = 3 -- nothing to do (e.g. no input items), or blocked anyhow (output jammed),
-- or node (world) not loaded
techage.FAULT = 4 -- any fault state (e.g. no fuel), which can be fixed by the player
techage.BLOCKED = 5 -- a pushing node is blocked due to a full destination inventory
techage.DEFECT = 6 -- a defect (broken), which has to be repaired by the player
techage.StatesImg = {
"tubelib_inv_button_off.png",
"tubelib_inv_button_on.png",
"tubelib_inv_button_standby.png",
"tubelib_inv_button_error.png",
"tubelib_inv_button_warning.png",
"tubelib_inv_button_off.png",
}
-- Return state button image for the node inventory
function techage.state_button(state)
if state and state < 7 and state > 0 then
return techage.StatesImg[state]
end
return "tubelib_inv_button_off.png"
end
-- State string based on button states
techage.StateStrings = {"stopped", "running", "standby", "fault", "blocked", "defect"}
--
-- Local States
--
local STOPPED = techage.STOPPED
local RUNNING = techage.RUNNING
local STANDBY = techage.STANDBY
local FAULT = techage.FAULT
local BLOCKED = techage.BLOCKED
local DEFECT = techage.DEFECT
local AGING_FACTOR = 4 -- defect random factor
--
-- NodeStates Class Functions
--
techage.NodeStates = {}
local NodeStates = techage.NodeStates
local function start_condition_fullfilled(pos, meta)
return true
end
function NodeStates:new(attr)
local o = {
-- mandatory
cycle_time = attr.cycle_time, -- for running state
standby_ticks = attr.standby_ticks, -- for standby state
has_item_meter = attr.has_item_meter, -- true/false
-- optional
node_name_passive = attr.node_name_passive,
node_name_active = attr.node_name_active,
node_name_defect = attr.node_name_defect,
infotext_name = attr.infotext_name,
start_condition_fullfilled = attr.start_condition_fullfilled or start_condition_fullfilled,
on_start = attr.on_start,
on_stop = attr.on_stop,
formspec_func = attr.formspec_func,
}
if attr.aging_factor then
o.aging_level1 = attr.aging_factor * techage.machine_aging_value
o.aging_level2 = attr.aging_factor * techage.machine_aging_value * AGING_FACTOR
end
setmetatable(o, self)
self.__index = self
return o
end
function NodeStates:node_init(pos, number)
local meta = M(pos)
meta:set_int("tubelib_state", STOPPED)
meta:set_string("tubelib_number", number)
if self.infotext_name then
meta:set_string("infotext", self.infotext_name.." "..number..": stopped")
end
if self.has_item_meter then
meta:set_int("tubelib_item_meter", 0)
end
if self.aging_level1 then
meta:set_int("tubelib_aging", 0)
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
end
function NodeStates:stop(pos, meta)
local state = meta:get_int("tubelib_state")
if state ~= DEFECT then
if self.on_stop then
self.on_stop(pos, meta, state)
end
meta:set_int("tubelib_state", STOPPED)
if self.node_name_passive then
local node = minetest.get_node(pos)
node.name = self.node_name_passive
minetest.swap_node(pos, node)
end
if self.infotext_name then
local number = meta:get_string("tubelib_number")
meta:set_string("infotext", self.infotext_name.." "..number..": stopped")
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
minetest.get_node_timer(pos):stop()
return true
end
return false
end
function NodeStates:start(pos, meta, called_from_on_timer)
local state = meta:get_int("tubelib_state")
if state == STOPPED or state == STANDBY or state == BLOCKED then
if not self.start_condition_fullfilled(pos, meta) then
return false
end
if self.on_start then
self.on_start(pos, meta, state)
end
meta:set_int("tubelib_state", RUNNING)
meta:set_int("tubelib_countdown", 4)
if called_from_on_timer then
-- timer has to be stopped once to be able to be restarted
self.stop_timer = true
end
if self.node_name_active then
local node = minetest.get_node(pos)
node.name = self.node_name_active
minetest.swap_node(pos, node)
end
if self.infotext_name then
local number = meta:get_string("tubelib_number")
meta:set_string("infotext", self.infotext_name.." "..number..": running")
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
minetest.get_node_timer(pos):start(self.cycle_time)
return true
end
return false
end
function NodeStates:standby(pos, meta)
if meta:get_int("tubelib_state") == RUNNING then
meta:set_int("tubelib_state", STANDBY)
-- timer has to be stopped once to be able to be restarted
self.stop_timer = true
if self.node_name_passive then
local node = minetest.get_node(pos)
node.name = self.node_name_passive
minetest.swap_node(pos, node)
end
if self.infotext_name then
local number = meta:get_string("tubelib_number")
meta:set_string("infotext", self.infotext_name.." "..number..": standby")
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks)
return true
end
return false
end
-- special case of standby for pushing nodes
function NodeStates:blocked(pos, meta)
if meta:get_int("tubelib_state") == RUNNING then
meta:set_int("tubelib_state", BLOCKED)
-- timer has to be stopped once to be able to be restarted
self.stop_timer = true
if self.node_name_passive then
local node = minetest.get_node(pos)
node.name = self.node_name_passive
minetest.swap_node(pos, node)
end
if self.infotext_name then
local number = meta:get_string("tubelib_number")
meta:set_string("infotext", self.infotext_name.." "..number..": blocked")
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks)
return true
end
return false
end
function NodeStates:fault(pos, meta)
if meta:get_int("tubelib_state") == RUNNING then
meta:set_int("tubelib_state", FAULT)
if self.node_name_passive then
local node = minetest.get_node(pos)
node.name = self.node_name_passive
minetest.swap_node(pos, node)
end
if self.infotext_name then
local number = meta:get_string("tubelib_number")
meta:set_string("infotext", self.infotext_name.." "..number..": fault")
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
minetest.get_node_timer(pos):stop()
return true
end
return false
end
function NodeStates:defect(pos, meta)
meta:set_int("tubelib_state", DEFECT)
if self.node_name_defect then
local node = minetest.get_node(pos)
node.name = self.node_name_defect
minetest.swap_node(pos, node)
end
if self.infotext_name then
local number = meta:get_string("tubelib_number")
meta:set_string("infotext", self.infotext_name.." "..number..": defect")
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
minetest.get_node_timer(pos):stop()
return true
end
function NodeStates:get_state(meta)
return meta:get_int("tubelib_state")
end
function NodeStates:get_state_string(meta)
return techage.StateStrings[meta:get_int("tubelib_state")]
end
function NodeStates:is_active(meta)
local state = meta:get_int("tubelib_state")
if self.stop_timer == true then
self.stop_timer = false
return false
end
return state == RUNNING or state == STANDBY or state == BLOCKED
end
-- To be called if node is idle.
-- If countdown reaches zero, the node is set to STANDBY.
function NodeStates:idle(pos, meta)
local countdown = meta:get_int("tubelib_countdown") - 1
meta:set_int("tubelib_countdown", countdown)
if countdown < 0 then
self:standby(pos, meta)
end
end
-- To be called after successful node action to raise the timer
-- and keep the node in state RUNNING
function NodeStates:keep_running(pos, meta, val, num_items)
num_items = num_items or 1
-- set to RUNNING if not already done
self:start(pos, meta, true)
meta:set_int("tubelib_countdown", val)
meta:set_int("tubelib_item_meter", meta:get_int("tubelib_item_meter") + (num_items or 1))
if self.aging_level1 then
local cnt = meta:get_int("tubelib_aging") + num_items
meta:set_int("tubelib_aging", cnt)
if (cnt > (self.aging_level1) and math.random(self.aging_level2/num_items) == 1)
or cnt >= 999999 then
self:defect(pos, meta)
end
end
end
-- Start/stop node based on button events.
-- if function returns false, no button was pressed
function NodeStates:state_button_event(pos, fields)
if fields.state_button ~= nil then
local state = self:get_state(M(pos))
if state == STOPPED or state == STANDBY or state == BLOCKED then
self:start(pos, M(pos))
elseif state == RUNNING or state == FAULT then
self:stop(pos, M(pos))
end
return true
end
return false
end
function NodeStates:get_state_button_image(meta)
local state = meta:get_int("tubelib_state")
return techage.state_button(state)
end
-- command interface
function NodeStates:on_receive_message(pos, topic, payload)
if topic == "on" then
self:start(pos, M(pos))
return true
elseif topic == "off" then
self:stop(pos, M(pos))
return true
elseif topic == "state" then
local node = minetest.get_node(pos)
if node.name == "ignore" then -- unloaded node?
return "blocked"
end
return self:get_state_string(M(pos))
elseif self.has_item_meter and topic == "counter" then
return M(pos):get_int("tubelib_item_meter")
elseif self.has_item_meter and topic == "clear_counter" then
M(pos):set_int("tubelib_item_meter", 0)
return true
elseif self.aging_level1 and topic == "aging" then
return M(pos):get_int("tubelib_aging")
end
end
-- repair corrupt node data and/or migrate node to state2
function NodeStates:on_node_load(pos, not_start_timer)
local meta = minetest.get_meta(pos)
-- legacy node number/state/counter?
local number = meta:get_string("number")
if number ~= "" and number ~= nil then
meta:set_string("tubelib_number", number)
meta:set_int("tubelib_state", techage.state(meta:get_int("running")))
if self.has_item_meter then
meta:set_int("tubelib_item_meter", meta:get_int("counter"))
end
if self.aging_level1 then
meta:set_int("tubelib_aging", 0)
end
meta:set_string("number", nil)
meta:set_int("running", 0)
meta:set_int("counter", 0)
end
-- node number corrupt?
number = meta:get_string("tubelib_number")
if number == "" then
number = techage.get_new_number(pos, self.node_name_passive)
meta:set_string("tubelib_number", number)
else
local info = techage.get_node_info(number)
if not info or info.pos ~= pos then
number = techage.get_new_number(pos, self.node_name_passive)
meta:set_string("tubelib_number", number)
end
end
-- state corrupt?
local state = meta:get_int("tubelib_state")
if state == 0 then
if minetest.get_node_timer(pos):is_started() then
meta:set_int("tubelib_state", RUNNING)
else
meta:set_int("tubelib_state", STOPPED)
end
elseif state == RUNNING and not not_start_timer then
minetest.get_node_timer(pos):start(self.cycle_time)
elseif state == STANDBY then
minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks)
elseif state == BLOCKED then
minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks)
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
end
-- Repair of defect (feature!) nodes
function NodeStates:on_node_repair(pos)
local meta = M(pos)
if meta:get_int("tubelib_state") == DEFECT then
meta:set_int("tubelib_state", STOPPED)
if self.node_name_passive then
local node = minetest.get_node(pos)
node.name = self.node_name_passive
minetest.swap_node(pos, node)
end
if self.aging_level1 then
meta:set_int("tubelib_aging", 0)
end
if self.infotext_name then
local number = meta:get_string("tubelib_number")
meta:set_string("infotext", self.infotext_name.." "..number..": stopped")
end
if self.formspec_func then
meta:set_string("formspec", self.formspec_func(self, pos, meta))
end
return true
end
return false
end
-- Return working or defect machine, depending on machine lifetime
function NodeStates:after_dig_node(pos, oldnode, oldmetadata, digger)
local inv = minetest.get_inventory({type="player", name=digger:get_player_name()})
local cnt = oldmetadata.fields.tubelib_aging and tonumber(oldmetadata.fields.tubelib_aging) or 0
local is_defect = cnt > self.aging_level1 and math.random(self.aging_level2 / cnt) == 1
if self.node_name_defect and is_defect then
inv:add_item("main", ItemStack(self.node_name_defect))
else
inv:add_item("main", ItemStack(self.node_name_passive))
end
end
-- Return "full", "loaded", or "empty" depending
-- on the number of fuel stack items.
-- Function only works on fuel inventories with one stacks/99 items
function techage.fuelstate(meta, listname, item)
if meta == nil or meta.get_inventory == nil then return nil end
local inv = meta:get_inventory()
if inv:is_empty(listname) then
return "empty"
end
local list = inv:get_list(listname)
if #list == 1 and list[1]:get_count() == 99 then
return "full"
else
return "loaded"
end
end

244
basis/power.lua Normal file
View File

@ -0,0 +1,244 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Power consumption for any kind of power distribution network
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local TP = function(pos) return minetest.registered_nodes[minetest.get_node(pos).name].techage end
local TN = function(node) return minetest.registered_nodes[node.name].techage end
-- Table to register the different power distribution network instances for global use
techage.Networks = {}
-- Used to determine the already passed nodes while power distribution
local Route = {}
local function pos_already_reached(pos)
local key = minetest.hash_node_position(pos)
if not Route[key] then
Route[key] = true
return false
end
return true
end
local DirToSide = {"B", "R", "F", "L", "D", "U"}
local function dir_to_side(pos, dir)
local node = minetest.get_node(pos)
if dir < 5 then
dir = (((dir - 1) - (node.param2 % 4)) % 4) + 1
end
return DirToSide[dir]
end
local SideToDir = {B=1, R=2, F=3, L=4, D=5, U=6}
local function side_to_dir(pos, side)
local node = minetest.get_node(pos)
local dir = SideToDir[side]
if dir < 5 then
dir = (((dir - 1) + (node.param2 % 4)) % 4) + 1
end
return dir
end
-- Calculate the power consumption on the given network
local function power_consumption(pos, dir)
if pos_already_reached(pos) then return 0 end
local mem = tubelib2.get_mem(pos)
local conn = mem.connections or {}
local val = 0
for fdir,fpos in pairs(conn) do
if fdir ~= tubelib2.Turn180Deg[dir or 0] then
local this = TP(fpos)
if this and this.power_consumption then
val = val + this.power_consumption(fpos, fdir)
else
val = val + power_consumption(fpos, fdir)
end
end
end
return val
end
local function turn_tube_on(pos, dir, network, on)
if network.switch_tube_line then
if on then
network:switch_tube_line(pos, dir, "on")
else
network:switch_tube_line(pos, dir, "off")
end
end
end
local function turn_on(pos, dir, on)
if pos_already_reached(pos) then return end
local mem = tubelib2.get_mem(pos)
local conn = mem.connections or {}
for fdir,fpos in pairs(conn) do
if fdir ~= tubelib2.Turn180Deg[dir or 0] then
local this = TP(fpos)
if this and this.turn_on then
this.turn_on(fpos, fdir, on)
end
if this and this.network then
turn_tube_on(pos, fdir, this.network, on)
end
turn_on(fpos, fdir, on)
end
end
end
-- power source: power > 0
-- power sink: power < 0
-- switched off: power = 0
local function sink_power_consumption(pos, power)
Route = {}
local sum = power + power_consumption(pos)
Route = {}
turn_on(pos, nil, sum > 0)
return sum
end
-- To be called from any generator
local function source_power_consumption(pos, mem)
local power = mem.power_produce or 0
mem.power_result = sink_power_consumption(pos, power)
return mem.power_result > 0
end
techage.sink_power_consumption = sink_power_consumption
techage.source_power_consumption = source_power_consumption
--
-- Generator with on power output side
--
function techage.generator_on(pos, power, network)
local mem = tubelib2.get_mem(pos)
mem.power_produce = power
return source_power_consumption(pos, mem)
end
function techage.generator_off(pos, network)
local mem = tubelib2.get_mem(pos)
mem.power_produce = 0
return source_power_consumption(pos, mem)
end
function techage.generator_power_consumption(pos, dir)
local mem = tubelib2.get_mem(pos)
if dir == tubelib2.Turn180Deg[mem.power_dir or 0] then
return mem.power_produce
end
return 0
end
function techage.generator_after_place_node(pos)
local mem = tubelib2.init_mem(pos)
mem.power_dir = side_to_dir(pos, TP(pos).side or 'R')
mem.power_produce = 0 -- will be set via generator_on
mem.power_result = 0
local network = TP(pos).network
network:after_place_node(pos)
end
function techage.generator_after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir)
-- check if contact side is correct
local mem = tubelib2.get_mem(pos)
if out_dir == mem.power_dir then
-- store connection for 'source_power_consumption()'
mem.connections = {[out_dir] = peer_pos}
source_power_consumption(pos, mem)
end
end
function techage.generator_on_destruct(pos)
techage.generator_off(pos)
end
function techage.generator_after_dig_node(pos, oldnode, oldmetadata, digger)
TN(oldnode).network:after_dig_node(pos)
tubelib2.del_mem(pos)
end
function techage.generator_formspec_level(mem)
print("generator_formspec_level", mem.power_result, mem.power_produce)
local percent = ((mem.power_result or 0) * 100) / (mem.power_produce or 1)
return "techage_form_level_bg.png^[lowpart:"..percent..":techage_form_level_fg.png]"
end
--
-- Distributor with 6 power input/output sides
--
function techage.distributor_power_consumption(pos, dir)
return power_consumption(pos, dir) - TP(pos).power_consume
end
function techage.distributor_after_place_node(pos, placer)
local this = TP(pos)
this.network:after_place_node(pos)
sink_power_consumption(pos, -this.power_consume)
end
function techage.distributor_after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir)
local mem = tubelib2.get_mem(pos)
mem.connections = mem.connections or {}
mem.connections[out_dir] = peer_pos
local sum = sink_power_consumption(pos, -TP(pos).power_consume)
end
function techage.distributor_on_destruct(pos)
sink_power_consumption(pos, -TP(pos).power_consume)
end
function techage.distributor_after_dig_node(pos, oldnode, oldmetadata, digger)
TN(oldnode).network:after_dig_node(pos)
tubelib2.del_mem(pos)
end
--
-- Consumer with on power input side (default)
--
function techage.consumer_power_consumption(pos)
return -TP(pos).power_consume
end
function techage.consumer_after_place_node(pos, placer)
local mem = tubelib2.init_mem(pos)
mem.power_dir = tubelib2.Turn180Deg[side_to_dir(pos, TP(pos).side or 'L')]
local this = TP(pos)
this.network:after_place_node(pos)
sink_power_consumption(pos, -this.power_consume)
end
function techage.consumer_after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir)
local mem = tubelib2.get_mem(pos)
mem.connections = mem.connections or {}
mem.connections[out_dir] = peer_pos
sink_power_consumption(pos, -TP(pos).power_consume)
end
function techage.consumer_on_destruct(pos)
sink_power_consumption(pos, -TP(pos).power_consume)
end
function techage.consumer_after_dig_node(pos, oldnode, oldmetadata, digger)
TN(oldnode).network:after_dig_node(pos)
tubelib2.del_mem(pos)
end

112
basis/trowel.lua Normal file
View File

@ -0,0 +1,112 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Trowel tool to hide/open cable/pipe/tube nodes
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
-- Overridden method of tubelib2!
function techage.get_primary_node_param2(pos, dir)
local npos = vector.add(pos, tubelib2.Dir6dToVector[dir or 0])
local param2 = M(npos):get_int("tl2_param2")
if param2 ~= 0 then
return param2, npos
end
end
-- Overridden method of tubelib2!
function techage.is_primary_node(pos, dir)
local npos = vector.add(pos, tubelib2.Dir6dToVector[dir or 0])
local param2 = M(npos):get_int("tl2_param2")
return param2 ~= 0
end
-- Determine if one node in the surrounding is a hidden tube/cable/pipe
local function other_hidden_nodes(pos, node_name)
return M({x=pos.x+1, y=pos.y, z=pos.z}):get_string(node_name) ~= "" or
M({x=pos.x-1, y=pos.y, z=pos.z}):get_string(node_name) ~= "" or
M({x=pos.x, y=pos.y+1, z=pos.z}):get_string(node_name) ~= "" or
M({x=pos.x, y=pos.y-1, z=pos.z}):get_string(node_name) ~= "" or
M({x=pos.x, y=pos.y, z=pos.z+1}):get_string(node_name) ~= "" or
M({x=pos.x, y=pos.y, z=pos.z-1}):get_string(node_name) ~= ""
end
local function hide_node(pos, node, meta, placer)
local inv = placer:get_inventory()
local stack = inv:get_stack("main", 1)
local taken = stack:take_item(1)
-- test if it is a simple node without logic
if taken:get_count() == 1
and minetest.registered_nodes[taken:get_name()]
and not minetest.registered_nodes[taken:get_name()].after_place_node
and not minetest.registered_nodes[taken:get_name()].on_construct then
meta:set_string("techage_hidden_nodename", node.name)
meta:set_string("techage_hidden_param2", node.param2)
local param2 = minetest.dir_to_facedir(placer:get_look_dir(), true)
minetest.swap_node(pos, {name = taken:get_name(), param2 = param2})
inv:set_stack("main", 1, stack)
end
end
local function open_node(pos, node, meta, placer)
local name = meta:get_string("techage_hidden_nodename")
local param2 = meta:get_string("techage_hidden_param2")
minetest.swap_node(pos, {name = name, param2 = param2})
meta:set_string("techage_hidden_nodename", "")
meta:set_string("techage_hidden_param2", "")
local inv = placer:get_inventory()
inv:add_item("main", ItemStack(node.name))
end
-- Hide or open a node
local function replace_node(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" then
local pos = pointed_thing.under
local meta = M(pos)
local node = minetest.get_node(pos)
if minetest.get_item_group(node.name, "techage_trowel") == 1 then
hide_node(pos, node, meta, placer)
elseif meta:get_string("techage_hidden_nodename") ~= "" then
open_node(pos, node, meta, placer)
end
end
end
minetest.register_node("techage:trowel", {
description = I("TechAge Trowel (uses items from the first, left inventory stack)"),
inventory_image = "techage_trowel.png",
wield_image = "techage_trowel.png",
use_texture_alpha = true,
groups = {cracky=1},
on_use = replace_node,
on_place = replace_node,
node_placement_prediction = "",
stack_max = 1,
})
minetest.register_on_dignode(function(pos, oldnode, digger)
-- If hidden nodes are arround, the removed one was probably
-- a hidden node, too.
if other_hidden_nodes(pos, "techage_hidden_nodename") then
-- test both hidden networks
techage.ElectricCable:after_dig_node("techage_hidden_nodename")
techage.BiogasPipe:after_dig_node("techage_hidden_nodename")
end
end)

132
basis/tubes.lua Normal file
View File

@ -0,0 +1,132 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Tubes based on tubelib2
]]--
-- used for registered nodes
techage.KnownNodes = {
["techage:tubeS"] = true,
["techage:tubeA"] = true,
}
local Tube = tubelib2.Tube:new({
-- North, East, South, West, Down, Up
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 200,
show_infotext = false,
primary_node_names = {"techage:tubeS", "techage:tubeA"},
after_place_tube = function(pos, param2, tube_type, num_tubes, tbl)
minetest.swap_node(pos, {name = "techage:tube"..tube_type, param2 = param2})
end,
})
techage.Tube = Tube
minetest.register_node("techage:tubeS", {
description = "TechAge Tube",
tiles = { -- Top, base, right, left, front, back
"techage_tube.png^[transformR90",
"techage_tube.png^[transformR90",
"techage_tube.png",
"techage_tube.png",
"techage_hole.png",
"techage_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Tube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-2/8, -2/8, -4/8, 2/8, 2/8, 4/8},
},
},
selection_box = {
type = "fixed",
fixed = { -1/4, -1/4, -1/2, 1/4, 1/4, 1/2 },
},
collision_box = {
type = "fixed",
fixed = { -1/4, -1/4, -1/2, 1/4, 1/4, 1/2 },
},
on_rotate = screwdriver.disallow,
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy=2, cracky=3, stone=1},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:tubeA", {
description = "TechAge Tube",
tiles = { -- Top, base, right, left, front, back
"techage_knee2.png",
"techage_hole2.png^[transformR180",
"techage_knee.png^[transformR270",
"techage_knee.png",
"techage_knee2.png",
"techage_hole2.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-2/8, -4/8, -2/8, 2/8, 2/8, 2/8},
{-2/8, -2/8, -4/8, 2/8, 2/8, -2/8},
},
},
selection_box = {
type = "fixed",
fixed = { -1/4, -1/2, -1/2, 1/4, 1/4, 1/4 },
},
collision_box = {
type = "fixed",
fixed = { -1/4, -1/2, -1/2, 1/4, 1/4, 1/4 },
},
on_rotate = screwdriver.disallow,
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy=2, cracky=3, stone=1, not_in_creative_inventory=1},
sounds = default.node_sound_wood_defaults(),
drop = "techage:tubeS",
})
minetest.register_craft({
output = "techage:tubeS 4",
recipe = {
{"default:steel_ingot", "", "group:wood"},
{"", "group:wood", ""},
{"group:wood", "", "default:tin_ingot"},
},
})

4
depends.txt Normal file
View File

@ -0,0 +1,4 @@
default
tubelib2
basic_materials

176
electric/electric_cable.lua Normal file
View File

@ -0,0 +1,176 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Cable and junction box for electrical power distribution
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local Cable = tubelib2.Tube:new({
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 1000,
show_infotext = false,
primary_node_names = {"techage:electric_cableS", "techage:electric_cableA"},
secondary_node_names = {"techage:lamp", "techage:lamp_on", "techage:power"},
after_place_tube = function(pos, param2, tube_type, num_tubes)
minetest.swap_node(pos, {name = "techage:electric_cable"..tube_type, param2 = param2 % 32})
M(pos):set_int("tl2_param2", param2)
end,
})
techage.ElectricCable = Cable
-- Overridden method of tubelib2!
function Cable:get_primary_node_param2(pos, dir)
return techage.get_primary_node_param2(pos, dir)
end
function Cable:is_primary_node(pos, dir)
return techage.is_primary_node(pos, dir)
end
Cable:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
minetest.registered_nodes[node.name].after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir)
end)
minetest.register_node("techage:electric_cableS", {
description = I("TA4 Electric Cable"),
tiles = {
-- up, down, right, left, back, front
"techage_electric_cable.png",
"techage_electric_cable.png",
"techage_electric_cable.png",
"techage_electric_cable.png",
"techage_electric_cable_end.png",
"techage_electric_cable_end.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Cable:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
if oldmetadata and oldmetadata.fields and oldmetadata.fields.tl2_param2 then
oldnode.param2 = oldmetadata.fields.tl2_param2
Cable:after_dig_tube(pos, oldnode)
end
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-3/32, -3/32, -4/8, 3/32, 3/32, 4/8},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, techage_trowel = 1},
sounds = default.node_sound_defaults(),
})
minetest.register_node("techage:electric_cableA", {
description = I("TA4 Electric Cable"),
tiles = {
-- up, down, right, left, back, front
"techage_electric_cable.png",
"techage_electric_cable_end.png",
"techage_electric_cable.png",
"techage_electric_cable.png",
"techage_electric_cable.png",
"techage_electric_cable_end.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
if oldmetadata and oldmetadata.fields and oldmetadata.fields.tl2_param2 then
oldnode.param2 = oldmetadata.fields.tl2_param2
Cable:after_dig_tube(pos, oldnode)
end
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-3/32, -4/8, -3/32, 3/32, 3/32, 3/32},
{-3/32, -3/32, -4/8, 3/32, 3/32, -3/32},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, techage_trowel = 1},
sounds = default.node_sound_defaults(),
drop = "techage:electric_cableS",
})
local size = 3/32
local Boxes = {
{{-size, -size, size, size, size, 0.5 }}, -- z+
{{-size, -size, -size, 0.5, size, size}}, -- x+
{{-size, -size, -0.5, size, size, size}}, -- z-
{{-0.5, -size, -size, size, size, size}}, -- x-
{{-size, -0.5, -size, size, size, size}}, -- y-
{{-size, -size, -size, size, 0.5, size}}, -- y+
}
techage.register_junction("techage:electric_junction", 2/8, Boxes, Cable, {
description = "Electricity Junction Box",
tiles = {"techage_electric_junction.png"},
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, techage_trowel = 1},
sounds = default.node_sound_defaults(),
after_place_node = function(pos, placer, itemstack, pointed_thing)
tubelib2.init_mem(pos)
Cable:after_place_node(pos)
techage.sink_power_consumption(pos, 0)
end,
after_tube_update = function(node, pos, out_dir, peer_pos, peer_in_dir)
local mem = tubelib2.get_mem(pos)
mem.connections = mem.connections or {}
mem.connections[out_dir] = peer_pos
local name = "techage:electric_junction"..techage.junction_type(mem.connections)
minetest.swap_node(pos, {name = name, param2 = 0})
techage.sink_power_consumption(pos, 0)
end,
on_destruct = function(pos)
techage.sink_power_consumption(pos, 0)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Cable:after_dig_node(pos)
end,
})

128
electric/test.lua Normal file
View File

@ -0,0 +1,128 @@
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local POWER_CONSUME = 1
local Cable = techage.ElectricCable
local function swap_node(pos, name)
local node = minetest.get_node(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function lamp_turn_on(pos, dir, on)
local mem = tubelib2.get_mem(pos)
if mem.power_dir == dir or mem.power_dir == tubelib2.Turn180Deg[dir] then
if on then
swap_node(pos, "techage:lamp_on")
else
swap_node(pos, "techage:lamp")
end
end
end
minetest.register_node("techage:lamp", {
description = "TechAge Lamp",
tiles = {
-- up, down, right, left, back, front
'techage_electric_button.png',
'techage_electric_button.png',
'techage_electric_button.png',
'techage_electric_button.png',
'techage_electric_button.png^techage_electric_plug.png',
'techage_electric_button.png^techage_electric_plug.png',
},
techage = {
turn_on = lamp_turn_on,
power_consumption = techage.consumer_power_consumption,
network = techage.ElectricCable,
power_consume = POWER_CONSUME,
side = 'B',
},
after_place_node = techage.consumer_after_place_node,
after_tube_update = techage.consumer_after_tube_update,
on_destruct = techage.consumer_on_destruct,
after_dig_node = techage.consumer_after_dig_node,
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:lamp_on", {
description = "TechAge Lamp",
tiles = {
'techage_electric_button.png',
},
techage = {
turn_on = lamp_turn_on,
power_consumption = techage.consumer_power_consumption,
network = techage.ElectricCable,
power_consume = POWER_CONSUME,
},
after_place_node = techage.consumer_after_place_node,
after_tube_update = techage.consumer_after_tube_update,
on_destruct = techage.consumer_on_destruct,
after_dig_node = techage.consumer_after_dig_node,
paramtype = "light",
light_source = LIGHT_MAX,
sunlight_propagates = true,
paramtype2 = "facedir",
drop = "techage:lamp",
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:power", {
description = "TechAge Power",
tiles = {
-- up, down, right, left, back, front
'techage_electric_button.png^techage_electric_power.png',
'techage_electric_button.png^techage_electric_power.png',
'techage_electric_button.png^techage_electric_power.png^techage_electric_plug.png',
'techage_electric_button.png^techage_electric_power.png',
'techage_electric_button.png^techage_electric_power.png',
'techage_electric_button.png^techage_electric_power.png',
},
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
techage = {
network = Cable,
power_consumption = techage.generator_power_consumption,
},
after_place_node = techage.generator_after_place_node,
after_tube_update = techage.generator_after_tube_update,
on_destruct = techage.generator_on_destruct,
after_dig_node = techage.generator_after_dig_node,
on_rightclick = function(pos, node, clicker)
local mem = tubelib2.get_mem(pos)
print("on_rightclick", mem.power)
if mem.power_produce and mem.power_produce > 0 then
techage.generator_off(pos)
else
techage.generator_on(pos, 8)
end
end,
})

205
fermenter/biogas_pipe.lua Normal file
View File

@ -0,0 +1,205 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Biogas pipes
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local Pipe = tubelib2.Tube:new({
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 1000,
show_infotext = false,
primary_node_names = {"techage:biogas_pipeS", "techage:biogas_pipeA"},
secondary_node_names = {"techage:gasflare", "techage:compressor"},
after_place_tube = function(pos, param2, tube_type, num_tubes, tbl)
minetest.swap_node(pos, {name = "techage:biogas_pipe"..tube_type, param2 = param2})
M(pos):set_int("tl2_param2", param2)
end,
})
Pipe:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
minetest.registered_nodes[node.name].after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir)
end)
techage.BiogasPipe = Pipe
-- Overridden method of tubelib2!
function Pipe:get_primary_node_param2(pos, dir)
return techage.get_primary_node_param2(pos, dir)
end
function Pipe:is_primary_node(pos, dir)
return techage.is_primary_node(pos, dir)
end
Pipe:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
local clbk = minetest.registered_nodes[node.name].after_tube_update
if clbk then
clbk(node, pos, out_dir, peer_pos, peer_in_dir)
else
techage.after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir)
end
end)
minetest.register_node("techage:biogas_pipeS", {
description = I("TA3 Biogas Pipe"),
tiles = {
"techage_gaspipe.png^[transformR90",
"techage_gaspipe.png^[transformR90",
"techage_gaspipe.png",
"techage_gaspipe.png",
"techage_gaspipe_hole2.png",
"techage_gaspipe_hole2.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Pipe:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
if oldmetadata and oldmetadata.fields and oldmetadata.fields.tl2_param2 then
oldnode.param2 = oldmetadata.fields.tl2_param2
Pipe:after_dig_tube(pos, oldnode)
end
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-1/8, -1/8, -4/8, 1/8, 1/8, 4/8},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly = 3, cracky = 3, snappy = 3, techage_trowel = 1},
sounds = default.node_sound_glass_defaults(),
})
minetest.register_node("techage:biogas_pipeA", {
description = I("TA3 Biogas Pipe"),
tiles = {
"techage_gaspipe_knee2.png",
"techage_gaspipe_hole2.png^[transformR180",
"techage_gaspipe_knee.png^[transformR270",
"techage_gaspipe_knee.png",
"techage_gaspipe_knee2.png",
"techage_gaspipe_hole2.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
if oldmetadata and oldmetadata.fields and oldmetadata.fields.tl2_param2 then
oldnode.param2 = oldmetadata.fields.tl2_param2
Pipe:after_dig_tube(pos, oldnode)
end
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-1/8, -4/8, -1/8, 1/8, 1/8, 1/8},
{-2/8, -0.5, -2/8, 2/8, -13/32, 2/8},
{-1/8, -1/8, -4/8, 1/8, 1/8, -1/8},
{-2/8, -2/8, -0.5, 2/8, 2/8, -13/32},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly = 3, cracky = 3, snappy = 3, techage_trowel = 1, not_in_creative_inventory=1},
sounds = default.node_sound_glass_defaults(),
drop = "techage:biogas_pipeS",
})
local size1 = 1/8
local size2 = 2/8
local size3 = 13/32
local Boxes = {
{
{-size1, -size1, size1, size1, size1, 0.5 }, -- z+
{-size2, -size2, size3, size2, size2, 0.5 }, -- z+
},
{
{-size1, -size1, -size1, 0.5, size1, size1}, -- x+
{ size3, -size2, -size2, 0.5, size2, size2}, -- x+
},
{
{-size1, -size1, -0.5, size1, size1, size1}, -- z-
{-size2, -size2, -0.5, size2, size2, -size3}, -- z-
},
{
{-0.5, -size1, -size1, size1, size1, size1}, -- x-
{-0.5, -size2, -size2, -size3, size2, size2}, -- x-
},
{
{-size1, -0.5, -size1, size1, size1, size1}, -- y-
{-size2, -0.5, -size2, size2, -size3, size2}, -- y-
},
{
{-size1, -size1, -size1, size1, 0.5, size1}, -- y+
{-size2, size3, -size2, size2, 0.5, size2}, -- y+
}
}
techage.register_junction("techage:biogas_junction", 1/8, Boxes, Pipe, {
description = "TA3 Biogas Junction",
tiles = {"techage_gaspipe_junction.png"},
groups = {crumbly = 3, cracky = 3, snappy = 3, techage_trowel = 1},
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Position "..S(pos))
Pipe:after_place_node(pos)
techage.sink_power_consumption(pos, 0)
end,
after_tube_update = function(node, pos, out_dir, peer_pos, peer_in_dir)
local conn = minetest.deserialize(M(pos):get_string("connections")) or {}
conn[out_dir] = peer_pos
M(pos):set_string("connections", minetest.serialize(conn))
local name = "techage:biogas_junction"..techage.junction_type(conn)
minetest.swap_node(pos, {name = name, param2 = 0})
techage.sink_power_consumption(pos, 0)
end,
on_destruct = function(pos)
techage.sink_power_consumption(pos, 0)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
end,
})

182
fermenter/gasflare.lua Normal file
View File

@ -0,0 +1,182 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
Biogas flare
]]--
local HEIGHT = 7
local function remove_flame(pos)
local idx
for idx=HEIGHT,1,-1 do
pos = {x=pos.x, y=pos.y+1, z=pos.z}
local node = minetest.get_node(pos)
if string.find(node.name, "techage:flame") then
minetest.remove_node(pos)
end
end
end
local function flame(pos)
local idx
for idx=HEIGHT,1,-1 do
pos = {x=pos.x, y=pos.y+1, z=pos.z}
idx = math.min(idx, 12)
local node = minetest.get_node(pos)
if node.name ~= "air" then
return
end
minetest.add_node(pos, {name = "techage:flame"..math.min(idx,7)})
local meta = minetest.get_meta(pos)
end
end
local lRatio = {120, 110, 95, 75, 55, 28, 0}
local lColor = {"000080", "400040", "800000", "800000", "800000", "800000", "800000"}
for idx,ratio in ipairs(lRatio) do
local color = "techage_flame_animated.png^[colorize:#"..lColor[idx].."B0:"..ratio
minetest.register_node("techage:flame"..idx, {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-3/8, -4/8, -2/8, 3/8, 4/8, 2/8},
{-2/8, -4/8, -3/8, 2/8, 4/8, 3/8},
},
},
tiles = {
{
name = color,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1
},
},
},
after_destruct = function(pos, oldnode)
pos.y = pos.y + 1
local node = minetest.get_node(pos)
if minetest.get_item_group(node.name, "techage_flame") > 0 then
minetest.remove_node(pos)
end
end,
use_texture_alpha = true,
inventory_image = "techage_flame.png",
paramtype = "light",
light_source = 13,
walkable = false,
pointable = false,
diggable = false,
buildable_to = true,
is_ground_content = false,
drop = "",
drowning = 1,
damage_per_second = 4 + idx,
groups = {igniter = 2, dig_immediate = 3, techage_flame=1, not_in_creative_inventory=1},
drop = "",
})
end
local function start_flarestack(pos, playername)
if minetest.is_protected(
{x=pos.x, y=pos.y+1, z=pos.z},
playername) then
return
end
local meta = minetest.get_meta(pos)
flame({x=pos.x, y=pos.y+1, z=pos.z})
local handle = minetest.sound_play("gasflare", {
pos = pos,
max_hear_distance = 20,
gain = 1,
loop = true})
print("handle", handle)
meta:set_int("handle", handle)
end
local function stop_flarestack(pos, handle)
remove_flame({x=pos.x, y=pos.y+1, z=pos.z})
minetest.sound_stop(handle)
end
minetest.register_node("techage:gasflare", {
description = "gas flare",
tiles = {
"techage_gasflare.png",
"techage_gasflare.png",
"techage_gasflare.png",
"techage_gasflare.png",
"techage_gasflare.png",
"techage_gasflare.png^techage_appl_hole2.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
local node = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
if node.name ~= "air" then
return
end
minetest.add_node({x=pos.x, y=pos.y+1, z=pos.z}, {name = "techage:gasflare2"})
end,
on_punch = function(pos, node, puncher)
local meta = minetest.get_meta(pos)
local handle = meta:get_int("handle")
minetest.sound_stop(handle)
start_flarestack(pos, puncher:get_player_name())
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
print(dump(oldmetadata))
stop_flarestack(pos, oldmetadata.fields.handle)
local node = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
if node.name == "techage:gasflare2" then
minetest.remove_node({x=pos.x, y=pos.y+1, z=pos.z})
end
end,
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:gasflare2", {
description = "",
tiles = {
"techage_gasflare.png^techage_appl_hole2.png",
"techage_gasflare.png"
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-1/8, -4/8, -1/8, 1/8, 4/8, 1/8},
{-4/8, 3/8, -4/8, 4/8, 4/8, 4/8},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
diggable = false,
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})

38
init.lua Normal file
View File

@ -0,0 +1,38 @@
techage = {
NodeDef = {}, -- node registration info
}
techage.max_num_forceload_blocks = tonumber(minetest.setting_get("techage_max_num_forceload_blocks")) or 12
techage.basalt_stone_enabled = minetest.setting_get("techage_basalt_stone_enabled") == "true"
techage.machine_aging_value = tonumber(minetest.setting_get("techage_machine_aging_value")) or 100
local MP = minetest.get_modpath("techage")
-- Load support for intllib.
dofile(MP.."/basis/intllib.lua")
dofile(MP.."/basis/power.lua") -- power distribution
dofile(MP.."/basis/trowel.lua") -- hidden networks
dofile(MP.."/basis/junction.lua") -- network junction box
-- Steam Engine
dofile(MP.."/steam_engine/drive_axle.lua")
dofile(MP.."/steam_engine/steam_pipe.lua")
dofile(MP.."/steam_engine/firebox.lua")
dofile(MP.."/steam_engine/boiler.lua")
--dofile(MP.."/steam_engine/cylinder.lua")
dofile(MP.."/steam_engine/flywheel.lua")
dofile(MP.."/steam_engine/gearbox.lua")
dofile(MP.."/electric/electric_cable.lua")
dofile(MP.."/electric/test.lua")
dofile(MP.."/fermenter/biogas_pipe.lua")
dofile(MP.."/fermenter/gasflare.lua")
dofile(MP.."/nodes/test.lua")
dofile(MP.."/mechanic/perf_test.lua")

3
intllib.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
../intllib/tools/xgettext.sh ./tube_api.lua ./internal1.lua ./internal2.lua

521
mechanic/distributor.lua Normal file
View File

@ -0,0 +1,521 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
distributor.lua:
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local N = minetest.get_node
local NUM_FILTER_ELEM = 6
local NUM_FILTER_SLOTS = 4
local COUNTDOWN_TICKS = 4
local STANDBY_TICKS = 8
local CYCLE_TIME = 2
local function formspec(self, pos, meta)
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
return "size[10.5,8.5]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;0,0;2,4;]"..
"image[2,1.5;1,1;tubelib_gui_arrow.png]"..
"image_button[2,3;1,1;"..self:get_state_button_image(meta)..";state_button;]"..
"checkbox[3,0;filter1;On;"..dump(filter[1]).."]"..
"checkbox[3,1;filter2;On;"..dump(filter[2]).."]"..
"checkbox[3,2;filter3;On;"..dump(filter[3]).."]"..
"checkbox[3,3;filter4;On;"..dump(filter[4]).."]"..
"image[4,0;0.3,1;tubelib_red.png]"..
"image[4,1;0.3,1;tubelib_green.png]"..
"image[4,2;0.3,1;tubelib_blue.png]"..
"image[4,3;0.3,1;tubelib_yellow.png]"..
"list[context;red;4.5,0;6,1;]"..
"list[context;green;4.5,1;6,1;]"..
"list[context;blue;4.5,2;6,1;]"..
"list[context;yellow;4.5,3;6,1;]"..
"list[current_player;main;1.25,4.5;8,4;]"..
"listring[context;src]"..
"listring[current_player;main]"
end
local State = tubelib.NodeStates:new({
node_name_passive = "tubelib:distributor",
node_name_active = "tubelib:distributor_active",
node_name_defect = "tubelib:distributor_defect",
infotext_name = "Tubelib Distributor",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
aging_factor = 10,
formspec_func = formspec,
})
-- Return a key/value table with all items and the corresponding stack numbers
local function invlist_content_as_kvlist(list)
local res = {}
for idx,items in ipairs(list) do
local name = items:get_name()
if name ~= "" then
res[name] = idx
end
end
return res
end
-- Return the total number of list entries
local function invlist_num_entries(list)
local res = 0
for _,items in ipairs(list) do
local name = items:get_name()
if name ~= "" then
res = res + items:get_count()
end
end
return res
end
-- Return a gapless table with all items
local function invlist_entries_as_list(list)
local res = {}
for _,items in ipairs(list) do
if items:get_count() > 0 then
res[#res+1] = {items:get_name(), items:get_count()}
end
end
return res
end
local function AddToTbl(kvTbl, new_items)
for _, l in ipairs(new_items) do
kvTbl[l[1]] = true
end
return kvTbl
end
-- return the number of items to be pushed to an unconfigured slot
local function num_items(moved_items, name, filter_item_names, rejected_item_names)
if filter_item_names[name] == nil then -- not configured in one filter?
if moved_items < MAX_NUM_PER_CYC then
return math.min(4, MAX_NUM_PER_CYC - moved_items)
end
end
if rejected_item_names[name] then -- rejected item from another slot?
if moved_items < MAX_NUM_PER_CYC then
return math.min(rejected_item_names[name], MAX_NUM_PER_CYC - moved_items)
end
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
local meta = M(pos)
local inv = meta:get_inventory()
local list = inv:get_list(listname)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "src" then
if State:get_state(M(pos)) == tubelib.STANDBY then
State:start(pos, meta)
end
return stack:get_count()
elseif invlist_num_entries(list) < MAX_NUM_PER_CYC then
return stack:get_count()
end
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local meta = M(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack(from_list, from_index)
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
local SlotColors = {"red", "green", "blue", "yellow"}
local Num2Ascii = {"B", "L", "F", "R"} -- color to side translation
local FilterCache = {} -- local cache for filter settings
local function filter_settings(pos)
local hash = minetest.hash_node_position(pos)
local meta = M(pos)
local inv = meta:get_inventory()
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
local kvFilterItemNames = {} -- {<item:name> = true,...}
local kvSide2ItemNames = {} -- {"F" = {<item:name>,...},...}
-- collect all filter settings
for idx,slot in ipairs(SlotColors) do
local side = Num2Ascii[idx]
if filter[idx] == true then
local list = inv:get_list(slot)
local filter = invlist_entries_as_list(list)
AddToTbl(kvFilterItemNames, filter)
kvSide2ItemNames[side] = filter
end
end
FilterCache[hash] = {
kvFilterItemNames = kvFilterItemNames,
kvSide2ItemNames = kvSide2ItemNames,
kvRejectedItemNames = {},
}
end
-- move items from configured filters to the output
local function distributing(pos, meta)
local player_name = meta:get_string("player_name")
local slot_idx = meta:get_int("slot_idx") or 1
meta:set_int("slot_idx", (slot_idx + 1) % NUM_FILTER_SLOTS)
local side = Num2Ascii[slot_idx+1]
local listname = SlotColors[slot_idx+1]
local inv = meta:get_inventory()
local list = inv:get_list("src")
local kvSrc = invlist_content_as_kvlist(list)
local counter = minetest.deserialize(meta:get_string("item_counter")) or
{red=0, green=0, blue=0, yellow=0}
-- calculate the filter settings only once
local hash = minetest.hash_node_position(pos)
if FilterCache[hash] == nil then
filter_settings(pos)
end
-- read data from Cache
-- all filter items as key/value {<item:name> = true,...}
local kvFilterItemNames = FilterCache[hash].kvFilterItemNames
-- filter items of one slot as list {{<item:name>, <num-items>},...}
local items = FilterCache[hash].kvSide2ItemNames[side]
-- rejected items from other filter slots
local rejected = FilterCache[hash].kvRejectedItemNames
if items == nil then return end
local moved_items_total = 0
if next(items) then
for _,item in ipairs(items) do
local name, num = item[1], item[2]
if kvSrc[name] then
local item = tubelib.get_this_item(meta, "src", kvSrc[name], num) -- <<=== tubelib
if item then
if not tubelib.push_items(pos, side, item, player_name) then -- <<=== tubelib
tubelib.put_item(meta, "src", item)
rejected[name] = num
else
counter[listname] = counter[listname] + num
moved_items_total = moved_items_total + num
end
end
end
end
end
-- move additional items from unconfigured filters to the output
if next(items) == nil then
local moved_items = 0
for name,_ in pairs(kvSrc) do
local num = num_items(moved_items, name, kvFilterItemNames, rejected)
if num then
local item = tubelib.get_this_item(meta, "src", kvSrc[name], num) -- <<=== tubelib
if item then
if not tubelib.push_items(pos, side, item, player_name) then -- <<=== tubelib
tubelib.put_item(meta, "src", item)
else
counter[listname] = counter[listname] + num
moved_items = moved_items + num
moved_items_total = moved_items_total + num
end
end
end
end
-- delete list for next slot round
if moved_items > 0 then
FilterCache[hash].kvRejectedItemNames = {}
end
end
meta:set_string("item_counter", minetest.serialize(counter))
if moved_items_total > 0 then
State:keep_running(pos, meta, COUNTDOWN_TICKS, moved_items_total)
else
State:idle(pos, meta)
end
end
-- move items to the output slots
local function keep_running(pos, elapsed)
local meta = M(pos)
distributing(pos, meta)
return State:is_active(meta)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
local filter = minetest.deserialize(meta:get_string("filter"))
if fields.filter1 ~= nil then
filter[1] = fields.filter1 == "true"
elseif fields.filter2 ~= nil then
filter[2] = fields.filter2 == "true"
elseif fields.filter3 ~= nil then
filter[3] = fields.filter3 == "true"
elseif fields.filter4 ~= nil then
filter[4] = fields.filter4 == "true"
end
meta:set_string("filter", minetest.serialize(filter))
filter_settings(pos)
if fields.state_button ~= nil then
State:state_button_event(pos, fields)
else
meta:set_string("formspec", formspec(State, pos, meta))
end
end
-- tubelib command to turn on/off filter channels
local function change_filter_settings(pos, slot, val)
local slots = {["red"] = 1, ["green"] = 2, ["blue"] = 3, ["yellow"] = 4}
local meta = M(pos)
local filter = minetest.deserialize(meta:get_string("filter"))
local num = slots[slot] or 1
if num >= 1 and num <= 4 then
filter[num] = val == "on"
end
meta:set_string("filter", minetest.serialize(filter))
filter_settings(pos)
meta:set_string("formspec", formspec(State, pos, meta))
return true
end
minetest.register_node("tubelib:distributor", {
description = "Tubelib Distributor",
tiles = {
-- up, down, right, left, back, front
'tubelib_distributor.png',
'tubelib_front.png',
'tubelib_distributor_yellow.png',
'tubelib_distributor_green.png',
"tubelib_distributor_red.png",
"tubelib_distributor_blue.png",
},
after_place_node = function(pos, placer)
local meta = M(pos)
local number = tubelib.add_node(pos, "tubelib:distributor") -- <<=== tubelib
local filter = {false,false,false,false}
meta:set_string("filter", minetest.serialize(filter))
State:node_init(pos, number)
meta:set_string("player_name", placer:get_player_name())
local inv = meta:get_inventory()
inv:set_size('src', 8)
inv:set_size('yellow', 6)
inv:set_size('green', 6)
inv:set_size('red', 6)
inv:set_size('blue', 6)
meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0}))
end,
on_receive_fields = on_receive_fields,
can_dig = function(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("src")
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
tubelib.remove_node(pos) -- <<=== tubelib
State:after_dig_node(pos, oldnode, oldmetadata, digger)
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
on_timer = keep_running,
on_rotate = screwdriver.disallow,
drop = "",
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("tubelib:distributor_active", {
description = "Tubelib Distributor",
tiles = {
-- up, down, right, left, back, front
{
image = "tubelib_distributor_active.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
'tubelib_front.png',
'tubelib_distributor_yellow.png',
'tubelib_distributor_green.png',
"tubelib_distributor_red.png",
"tubelib_distributor_blue.png",
},
on_receive_fields = on_receive_fields,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
on_timer = keep_running,
on_rotate = screwdriver.disallow,
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {crumbly=0, not_in_creative_inventory=1},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("tubelib:distributor_defect", {
description = "Tubelib Distributor",
tiles = {
-- up, down, right, left, back, front
'tubelib_distributor.png',
'tubelib_front.png',
'tubelib_distributor_yellow.png^tubelib_defect.png',
'tubelib_distributor_green.png^tubelib_defect.png',
"tubelib_distributor_red.png^tubelib_defect.png",
"tubelib_distributor_blue.png^tubelib_defect.png",
},
after_place_node = function(pos, placer)
local meta = M(pos)
local number = tubelib.add_node(pos, "tubelib:distributor") -- <<=== tubelib
State:node_init(pos, number)
meta:set_string("player_name", placer:get_player_name())
local filter = {false,false,false,false}
meta:set_string("filter", minetest.serialize(filter))
local inv = meta:get_inventory()
inv:set_size('src', 8)
inv:set_size('yellow', 6)
inv:set_size('green', 6)
inv:set_size('red', 6)
inv:set_size('blue', 6)
meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0}))
State:defect(pos, meta)
end,
on_receive_fields = on_receive_fields,
can_dig = function(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("src")
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
tubelib.remove_node(pos) -- <<=== tubelib
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
on_rotate = screwdriver.disallow,
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = "tubelib:distributor 2",
recipe = {
{"group:wood", "default:steel_ingot", "group:wood"},
{"tubelib:tubeS", "default:mese_crystal", "tubelib:tubeS"},
{"group:wood", "default:steel_ingot", "group:wood"},
},
})
--------------------------------------------------------------- tubelib
tubelib.register_node("tubelib:distributor",
{"tubelib:distributor_active", "tubelib:distributor_defect"}, {
on_pull_item = function(pos, side)
return tubelib.get_item(M(pos), "src")
end,
on_push_item = function(pos, side, item)
return tubelib.put_item(M(pos), "src", item)
end,
on_unpull_item = function(pos, side, item)
return tubelib.put_item(M(pos), "src", item)
end,
on_recv_message = function(pos, topic, payload)
if topic == "filter" then
return change_filter_settings(pos, payload.slot, payload.val)
elseif topic == "counter" then
local meta = minetest.get_meta(pos)
return minetest.deserialize(meta:get_string("item_counter")) or
{red=0, green=0, blue=0, yellow=0}
elseif topic == "clear_counter" then
local meta = minetest.get_meta(pos)
meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0}))
else
local resp = State:on_receive_message(pos, topic, payload)
if resp then
return resp
else
return "unsupported"
end
end
end,
on_node_load = function(pos)
State:on_node_load(pos)
end,
on_node_repair = function(pos)
return State:on_node_repair(pos)
end,
})
--------------------------------------------------------------- tubelib

91
mechanic/perf_test.lua Normal file
View File

@ -0,0 +1,91 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
distributor.lua:
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local N = minetest.get_node
local function formspec()
return "size[10.5,8.5]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;0,0;2,4;]"..
"list[current_player;main;1.25,4.5;8,4;]"..
"listring[context;src]"..
"listring[current_player;main]"
end
-- move items to the output slots
local function keep_running(pos, elapsed)
local meta = M(pos)
local inv = meta:get_inventory()
local name, num
for i = 1,10 do
--local list = inv:get_list("src")
for i = 1,8 do
--local stack = list[i]
local stack = inv:get_stack("src", i)
if stack:get_count() > 0 then
local taken = inv:remove_item("src", stack)
num = taken:get_count()
inv:add_item("src", taken)
break
end
end
end
return true
end
local function after_place_node(pos, placer)
local meta = M(pos)
local inv = meta:get_inventory()
inv:set_size('src', 8)
inv:add_item("src", ItemStack("wool:blue"))
inv:add_item("src", ItemStack("wool:red"))
inv:add_item("src", ItemStack("wool:green"))
meta:set_string("formspec", formspec())
minetest.get_node_timer(pos):start(0.1)
end
minetest.register_node("techage:perf_test", {
description = "perf_test",
tiles = {"techage_filling_ta2.png"},
after_place_node = after_place_node,
on_timer = keep_running,
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
})
minetest.register_lbm({
label = "[TechAge] Node update",
name = "techage:perf_test",
nodenames = {"techage:perf_test"},
run_at_every_load = true,
action = function(pos, node)
after_place_node(pos)
end
})

1
mod.conf Normal file
View File

@ -0,0 +1 @@
name = techage

124
models/techage_boiler.obj Normal file
View File

@ -0,0 +1,124 @@
# Blender v2.78 (sub 0) OBJ File: 'test.blend'
# www.blender.org
o Cylinder
v 0.000000 -0.500000 -0.450000
v 0.000000 0.500000 -0.450000
v 0.172208 -0.500000 -0.415746
v 0.172208 0.500000 -0.415746
v 0.318198 -0.500000 -0.318198
v 0.318198 0.500000 -0.318198
v 0.415746 -0.500000 -0.172208
v 0.415746 0.500000 -0.172208
v 0.450000 -0.500000 0.000000
v 0.450000 0.500000 0.000000
v 0.415746 -0.500000 0.172208
v 0.415746 0.500000 0.172208
v 0.318198 -0.500000 0.318198
v 0.318198 0.500000 0.318198
v 0.172208 -0.500000 0.415746
v 0.172208 0.500000 0.415746
v 0.000000 -0.500000 0.450000
v 0.000000 0.500000 0.450000
v -0.172207 -0.500000 0.415746
v -0.172207 0.500000 0.415746
v -0.318198 -0.500000 0.318198
v -0.318198 0.500000 0.318198
v -0.415746 -0.500000 0.172208
v -0.415746 0.500000 0.172208
v -0.450000 -0.500000 -0.000000
v -0.450000 0.500000 -0.000000
v -0.415746 -0.500000 -0.172208
v -0.415746 0.500000 -0.172208
v -0.318198 -0.500000 -0.318198
v -0.318198 0.500000 -0.318198
v -0.172207 -0.500000 -0.415746
v -0.172207 0.500000 -0.415746
vt 0.5486 0.5000
vt 0.5486 1.0000
vt 0.4725 1.0000
vt 0.4725 0.5000
vt 0.4142 1.0000
vt 0.4142 0.5000
vt 1.0000 0.5000
vt 1.0000 1.0000
vt 0.9239 1.0000
vt 0.9239 0.5000
vt 0.8415 1.0000
vt 0.8415 0.5000
vt 0.7654 1.0000
vt 0.7654 0.5000
vt 0.4142 0.5000
vt 0.4142 0.0000
vt 0.4725 0.0000
vt 0.4725 0.5000
vt 0.5486 0.0000
vt 0.5486 0.5000
vt 0.6310 0.0000
vt 0.6310 0.5000
vt 0.7071 0.0000
vt 0.7071 0.5000
vt 0.7654 0.0000
vt 0.7654 0.5000
vt 0.8415 0.0000
vt 0.8415 0.5000
vt 0.9239 0.0000
vt 0.9239 0.5000
vt 1.0000 0.0000
vt 1.0000 0.5000
vt 0.7654 0.5000
vt 0.7654 1.0000
vt 0.7071 1.0000
vt 0.7071 0.5000
vt 0.3244 0.4749
vt 0.3827 0.5370
vt 0.4142 0.6181
vt 0.4142 0.7059
vt 0.3827 0.7870
vt 0.3244 0.8491
vt 0.2483 0.8827
vt 0.1659 0.8827
vt 0.0898 0.8491
vt 0.0315 0.7870
vt 0.0000 0.7059
vt 0.0000 0.6181
vt 0.0315 0.5370
vt 0.0898 0.4749
vt 0.1659 0.4414
vt 0.2483 0.4414
vt 0.6310 1.0000
vt 0.6310 0.5000
vt 0.0000 0.2646
vt 0.0000 0.1768
vt 0.0315 0.0957
vt 0.0898 0.0336
vt 0.1659 0.0000
vt 0.2483 0.0000
vt 0.3244 0.0336
vt 0.3827 0.0957
vt 0.4142 0.1768
vt 0.4142 0.2646
vt 0.3827 0.3457
vt 0.3244 0.4078
vt 0.2483 0.4414
vt 0.1659 0.4414
vt 0.0898 0.4078
vt 0.0315 0.3457
s off
f 1/1 2/2 4/3 3/4
f 3/4 4/3 6/5 5/6
f 5/7 6/8 8/9 7/10
f 7/10 8/9 10/11 9/12
f 9/12 10/11 12/13 11/14
f 11/15 12/16 14/17 13/18
f 13/18 14/17 16/19 15/20
f 15/20 16/19 18/21 17/22
f 17/22 18/21 20/23 19/24
f 19/24 20/23 22/25 21/26
f 21/26 22/25 24/27 23/28
f 23/28 24/27 26/29 25/30
f 25/30 26/29 28/31 27/32
f 27/33 28/34 30/35 29/36
f 4/37 2/38 32/39 30/40 28/41 26/42 24/43 22/44 20/45 18/46 16/47 14/48 12/49 10/50 8/51 6/52
f 29/36 30/35 32/53 31/54
f 31/54 32/53 2/2 1/1
f 1/55 3/56 5/57 7/58 9/59 11/60 13/61 15/62 17/63 19/64 21/65 23/66 25/67 27/68 29/69 31/70

549
nodes/test.lua Normal file
View File

@ -0,0 +1,549 @@
minetest.register_node("techage:block1", {
description = "block1",
tiles = {"techage_filling_ta2.png^techage_frame_ta2.png"},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:block2", {
description = "block2",
tiles = {"techage_filling_ta3.png^techage_frame_ta3.png"},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:block3", {
description = "block3",
tiles = {
"techage_top_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:block4", {
description = "block4",
tiles = {
-- up, down, right, left, back, front
'techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_arrow.png',
'techage_filling_ta2.png^techage_frame_ta2.png',
'techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_outp.png',
'techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_inp.png',
{
image = "techage_pusher14.png^[transformR180]^techage_frame14_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
{
image = "techage_pusher14.png^techage_frame14_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:block5", {
description = "block5",
tiles = {
-- up, down, right, left, back, front
'techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_arrow.png',
'techage_filling_ta3.png^techage_frame_ta3.png',
'techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_outp.png',
'techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_inp.png',
{
image = "techage_pusher14.png^[transformR180]^techage_frame14_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
{
image = "techage_pusher14.png^techage_frame14_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:block6", {
description = "block6",
tiles = {
-- up, down, right, left, back, front
'techage_filling_ta4.png^techage_top_ta4.png^techage_appl_arrow.png',
'techage_filling_ta4.png^techage_frame_ta4.png',
'techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_outp.png',
'techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_inp.png',
{
image = "tubelib_pusher.png^[transformR180]^techage_frame14_ta4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
{
image = "tubelib_pusher.png^techage_frame14_ta4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:block7", {
description = "block7",
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_chest_front_ta3.png",
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:block8", {
description = "block8",
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_chest_back_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_chest_front_ta3.png",
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:block9", {
description = "block9",
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_top_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_chest_front_ta4.png",
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:sieve", {
description = "sieve",
drawtype = "nodebox",
tiles = {
-- up, down, right, left, back, front
'techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_inp.png',
'techage_filling_ta2.png^techage_frame_ta2.png',
'techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_outp.png',
'techage_filling_ta2.png^techage_frame_ta2.png',
{
image = "techage_filling4_ta2.png^techage_appl_sieve4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2,
},
},
{
image = "techage_filling4_ta2.png^techage_appl_sieve4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:sieve2", {
description = "sieve",
drawtype = "nodebox",
tiles = {
-- up, down, right, left, back, front
'techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_inp.png',
'techage_filling_ta3.png^techage_frame_ta3.png',
'techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_outp.png',
'techage_filling_ta3.png^techage_frame_ta3.png',
{
image = "techage_filling4_ta3.png^techage_appl_sieve4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2,
},
},
{
image = "techage_filling4_ta3.png^techage_appl_sieve4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:sieve3", {
description = "sieve",
drawtype = "nodebox",
tiles = {
-- up, down, right, left, back, front
'techage_filling_ta4.png^techage_top_ta4.png^techage_appl_inp.png',
'techage_filling_ta4.png^techage_frame_ta4.png',
'techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_outp.png',
'techage_filling_ta4.png^techage_frame_ta4.png',
{
image = "techage_filling4_ta4.png^techage_appl_sieve4.png^techage_frame4_ta4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2,
},
},
{
image = "techage_filling4_ta4.png^techage_appl_sieve4.png^techage_frame4_ta4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:filler", {
description = "filler",
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_arrow.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_hole2.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_inp.png",
--"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_filler.png",
--"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_filler.png",
{
image = "techage_filling4_ta3.png^techage_appl_filler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
{
image = "techage_filling4_ta3.png^techage_appl_filler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:compressor", {
description = "compressor",
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_arrow.png",
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_hole2.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_hole2.png",
--"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_compressor.png",
--"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_compressor.png^[transformFX]",
{
image = "techage_filling4_ta3.png^techage_appl_compressor4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.2,
},
},
{
image = "techage_filling4_ta3.png^techage_appl_compressor4.png^[transformFX]^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.2,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:fermenter", {
description = "fermenter",
tiles = {"techage_fermenter.png"},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:fermenter_foil", {
description = "fermenter_foil",
tiles = {"techage_fermenter_foil.png"},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
--sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("techage:biomass", {
description = "biomass",
drawtype = "liquid",
tiles = {
{
name = "techage_biomass.png",
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 4.0,
},
},
},
special_tiles = {
-- New-style water source material (mostly unused)
{
name = "techage_biomass.png",
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 4.0,
},
backface_culling = false,
},
},
on_timer = function(pos)
minetest.remove_node(pos)
return false
end,
after_place_node = function(pos, placer)
minetest.get_node_timer(pos):start(5)
end,
--alpha = 160,
paramtype = "light",
walkable = false,
pointable = false,
diggable = false,
buildable_to = true,
is_ground_content = false,
drop = "",
drowning = 1,
liquidtype = "source",
liquid_alternative_flowing = "techage:biomass_flowing",
liquid_alternative_source = "techage:biomass",
liquid_viscosity = 1,
post_effect_color = {a = 103, r = 30, g = 60, b = 90},
groups = {water = 3, liquid = 3, puts_out_fire = 1, cools_lava = 1},
sounds = default.node_sound_water_defaults(),
})
minetest.register_node("techage:biomass_flowing", {
description = "biomass",
drawtype = "flowingliquid",
tiles = {"default_water.png"},
special_tiles = {
{
name = "techage_biomass.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 4,
},
},
{
name = "techage_biomass.png",
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 4,
},
},
},
--alpha = 220,
paramtype = "light",
paramtype2 = "flowingliquid",
walkable = false,
pointable = false,
diggable = false,
buildable_to = true,
is_ground_content = false,
drop = "",
drowning = 1,
liquidtype = "flowing",
liquid_alternative_flowing = "techage:biomass_flowing",
liquid_alternative_source = "techage:biomass",
liquid_viscosity = 1,
post_effect_color = {a = 103, r = 30, g = 60, b = 90},
groups = {water = 3, liquid = 3, puts_out_fire = 1,
not_in_creative_inventory = 0, cools_lava = 1},
sounds = default.node_sound_water_defaults(),
})

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

10
settingtypes.txt Normal file
View File

@ -0,0 +1,10 @@
# Maximim number of Forceload Blocks per player (default 12)
tubelib_max_num_forceload_blocks (max number of Forceload Blocks) int 12
# Enable Basalt Stone (and disable ore generation via cobble generator)
tubelib_basalt_stone_enabled (Basalt Stone enabled) bool true
# This aging value is used to calculate the lifetime of machines before
# they go defect . The value 200 (default) results in a lifetime
# for standard machines of about 2000 - 8000 item processing cycles.
tubelib_machine_aging_value (machine aging value) int 200

BIN
sounds/techage_button.ogg Normal file

Binary file not shown.

BIN
sounds/techage_gasflare.ogg Normal file

Binary file not shown.

293
steam_engine/boiler.lua Normal file
View File

@ -0,0 +1,293 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
TA2 Steam Engine Boiler
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local CYCLE_TIME = 4
local HEAT_STEP = 10
local WATER_CONSUMPTION = 2
local MAX_WATER = 10
local POWER = 10
local Water = {
["bucket:bucket_river_water"] = true,
["bucket:bucket_water"] = true,
["bucket:bucket_empty"] = true,
}
local function formspec(mem)
local temp = mem.temperature or 20
local button = mem.running and I("Stop") or I("Start")
return "size[8,7]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"image_button[0,0.2;1,1;techage_form_inventory.png;storage;;true;false;]"..
"list[context;water;1,0.2;1,1;]"..
"image_button[0,1.6;1,1;techage_form_input.png;input;;true;false;]"..
"list[context;input;1,1.6;1,1;]"..
"image[1,1.6;1,1;bucket_water.png]"..
"image[1,1.6;1,1;techage_form_mask.png]"..
"image[3,0.5;1,2;techage_form_temp_bg.png^[lowpart:"..
temp..":techage_form_temp_fg.png]"..
"image[4,0.5;1,2;"..techage.generator_formspec_level(mem)..
"button[6,0.5;2,1;start;"..button.."]"..
"button[6,1.5;2,1;update;"..I("Update").."]"..
"list[current_player;main;0,3;8,4;]"..
"listring[current_name;water]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 3)
end
local function can_dig(pos, player)
local inv = M(pos):get_inventory()
local mem = tubelib2.get_mem(pos)
return inv:is_empty("water") and inv:is_empty("input") and not mem.running
end
local function move_to_water(pos)
local inv = M(pos):get_inventory()
local water_stack = inv:get_stack("water", 1)
local input_stack = inv:get_stack("input", 1)
if input_stack:get_name() == "bucket:bucket_empty" and input_stack:get_count() == 1 then
if water_stack:get_count() > 0 then
water_stack:set_count(water_stack:get_count() - 1)
input_stack = ItemStack("bucket:bucket_water")
inv:set_stack("water", 1, water_stack)
inv:set_stack("input", 1, input_stack)
end
elseif water_stack:get_count() < MAX_WATER then
if water_stack:get_count() == 0 then
water_stack = ItemStack("default:water_source")
else
water_stack:set_count(water_stack:get_count() + 1)
end
input_stack = ItemStack("bucket:bucket_empty")
inv:set_stack("water", 1, water_stack)
inv:set_stack("input", 1, input_stack)
end
end
local function start_boiler(pos)
local mem = tubelib2.get_mem(pos)
mem.water_level = mem.water_level or 0
local inv = M(pos):get_inventory()
local water_stack = inv:get_stack("water", 1)
print("trigger_boiler", mem.fire_trigger, mem.water_level, water_stack:get_count())
if mem.fire_trigger and (mem.water_level > 0 or water_stack:get_count() > 0) then
if not minetest.get_node_timer(pos):is_started() then
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "input" and Water[stack:get_name()] then
start_boiler(pos)
return stack:get_count()
end
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "input" then
return stack:get_count()
end
return 0
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
if fields.update then
local mem = tubelib2.get_mem(pos)
M(pos):set_string("formspec", formspec(mem))
end
if fields.start then
local mem = tubelib2.get_mem(pos)
mem.running = not (mem.running or false)
if mem.running then
techage.generator_on(pos, POWER)
else
techage.generator_off(pos)
end
M(pos):set_string("formspec", formspec(mem))
end
end
local function on_rightclick(pos, node, clicker)
local mem = tubelib2.get_mem(pos)
M(pos):set_string("formspec", formspec(mem))
end
local function get_water(pos)
local inv = M(pos):get_inventory()
local items = inv:get_stack("water", 1)
if items:get_count() > 0 then
local taken = items:take_item(1)
inv:set_stack("water", 1, items)
return true
end
return false
end
local function node_timer(pos)
local mem = tubelib2.get_mem(pos)
mem.temperature = mem.temperature or 20
mem.water_level = math.max((mem.water_level or 0) - WATER_CONSUMPTION, 0)
print(mem.fire_trigger, mem.running, mem.temperature, mem.water_level)
if mem.fire_trigger then
mem.temperature = math.min(mem.temperature + HEAT_STEP, 100)
else
mem.temperature = math.max(mem.temperature - HEAT_STEP, 20)
end
if mem.water_level == 0 then
if get_water(pos) then
mem.water_level = 100
else
mem.temperature = 20
end
end
if mem.temperature > 80 and mem.running then
techage.generator_on(pos, POWER)
else
techage.generator_off(pos)
end
mem.fire_trigger = false
return mem.temperature > 20
end
minetest.register_node("techage:boiler", {
description = I("TA2 Boiler"),
tiles = {"techage_boiler.png"},
drawtype = "mesh",
mesh = "techage_boiler.obj",
selection_box = {
type = "fixed",
fixed = {-10/32, -16/32, -10/32, 10/32, 46/32, 10/32},
},
can_dig = can_dig,
on_timer = node_timer,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
techage = {
network = techage.SteamPipe,
power_consumption = function(pos, dir)
techage.generator_power_consumption(pos, dir)
end,
trigger_boiler = function(pos)
local mem = tubelib2.get_mem(pos)
mem.fire_trigger = true
start_boiler(pos)
end,
},
on_destruct = function(pos)
techage.generator_on_destruct({x=pos.x, y=pos.y+1, z=pos.z})
end,
on_construct = function(pos)
local inv = M(pos):get_inventory()
inv:set_size('water', 1)
inv:set_size('input', 1)
local node = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
if node.name ~= "air" then
return
end
minetest.add_node({x=pos.x, y=pos.y+1, z=pos.z}, {name = "techage:boiler2", param2 = minetest.get_node(pos).param2})
end,
after_place_node = function(pos, placer, pointed_thing)
techage.generator_after_place_node({x=pos.x, y=pos.y+1, z=pos.z}, placer)
local mem = tubelib2.get_mem(pos)
mem.running = false
mem.water_level = 0
mem.temperatur = 20
M(pos):set_string("formspec", formspec(mem))
end,
on_metadata_inventory_put = function(pos)
minetest.after(0.5, move_to_water, pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local node = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
if node.name == "techage:boiler2" then
minetest.remove_node({x=pos.x, y=pos.y+1, z=pos.z})
techage.generator_after_dig_node({x=pos.x, y=pos.y+1, z=pos.z}, oldnode, oldmetadata, digger)
end
end,
paramtype2 = "facedir",
groups = {cracky=1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
-- boiler2
minetest.register_node("techage:boiler2", {
description = ("TA2 Boiler"),
tiles = {"techage_boiler2.png"},
drawtype = "mesh",
mesh = "techage_boiler.obj",
selection_box = {
type = "fixed",
fixed = {-10/32, -16/32, -10/32, 10/32, 16/32, 10/32},
},
techage = {
network = techage.SteamPipe,
power_consumption = function(pos, dir)
techage.generator_power_consumption({x=pos.x, y=pos.y-1, z=pos.z}, dir)
end,
},
after_tube_update = function(node, pos, out_dir, peer_pos, peer_in_dir)
techage.generator_after_tube_update(node,
{x=pos.x, y=pos.y-1, z=pos.z}, out_dir, peer_pos, peer_in_dir)
end,
diggable = false,
--pointable = false,
groups = {not_in_creative_inventory = 1},
})

103
steam_engine/cylinder.lua Normal file
View File

@ -0,0 +1,103 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
TA2 Steam Engine Cylinder
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local function can_dig(pos, player)
local inv = M(pos):get_inventory()
return inv:is_empty("fuel")
end
local function swap_node(pos, name)
local node = minetest.get_node(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function node_timer(pos, elapsed)
local mem = tubelib2.get_mem(pos)
local inv = M(pos):get_inventory()
local fuellist = inv:get_list("fuel")
end
minetest.register_node("techage:cylinder", {
description = I("TA2 Cylinder"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_cylinder.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_cylinder.png^techage_frame_ta2.png",
},
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:cylinder_on", {
description = I("TA2 Cylinder"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
{
image = "techage_filling4_ta2.png^techage_cylinder4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
{
image = "techage_filling4_ta2.png^techage_cylinder4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
},
paramtype = "light",
light_source = 0,
sunlight_propagates = true,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2, crumbly=2, choppy=2, not_in_creative_inventory = 1},
drop = "techage:cylinder",
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})

177
steam_engine/drive_axle.lua Normal file
View File

@ -0,0 +1,177 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
TA2 Drive Axles for the Steam Engine
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local Axle = tubelib2.Tube:new({
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 5,
show_infotext = false,
primary_node_names = {"techage:axle", "techage:axle_on"},
secondary_node_names = {"techage:flywheel", "techage:flywheel_on", "techage:gearbox", "techage:gearbox_on"},
after_place_tube = function(pos, param2, tube_type, num_tubes, state)
if state == "on" then
minetest.swap_node(pos, {name = "techage:axle_on", param2 = param2})
else
minetest.swap_node(pos, {name = "techage:axle", param2 = param2})
end
end,
})
Axle:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
minetest.registered_nodes[node.name].after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir)
end)
techage.Axle = Axle
minetest.register_node("techage:axle", {
description = I("TA2 Drive Axle"),
tiles = {
"techage_axleR.png",
"techage_axleR.png",
"techage_axle.png",
"techage_axle.png",
"techage_axle_clutch.png",
"techage_axle_clutch.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Axle:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Axle:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-3/16, -3/16, -4/8, 3/16, 3/16, 4/8},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly = 3, cracky = 3, snappy = 3},
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:axle_on", {
description = I("TA2 Drive Axle"),
tiles = {
{
image = "techage_axle4R.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
{
image = "techage_axle4R.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
{
image = "techage_axle4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
{
image = "techage_axle4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
{
image = "techage_axle_clutch4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
{
image = "techage_axle_clutch4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Axle:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Axle:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-3/16, -3/16, -4/8, 3/16, 3/16, 4/8},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
diggable = false,
groups = {not_in_creative_inventory = 1},
sounds = default.node_sound_metal_defaults(),
})

208
steam_engine/firebox.lua Normal file
View File

@ -0,0 +1,208 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
TA2 Steam Engine Firebox
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
local TP = function(pos) return minetest.registered_nodes[minetest.get_node(pos).name].techage end
local TN = function(node) return minetest.registered_nodes[node.name].techage end
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local CYCLE_TIME = 2
local BURN_CYCLES = 10
local Fuels = {
["techage:charcoal"] = true,
["default:coal_lump"] = true,
["default:coalblock"] = true,
}
local function formspec(mem)
local fuel_percent = 0
if mem.running then
fuel_percent = (mem.burn_cycles * 100) / BURN_CYCLES
end
return "size[8,6]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[current_name;fuel;1,0.5;1,1;]"..
"image[3,0.5;1,1;default_furnace_fire_bg.png^[lowpart:"..
fuel_percent..":default_furnace_fire_fg.png]"..
"button[5,0.5;1.8,1;update;"..I("Update").."]"..
"list[current_player;main;0,2;8,4;]"..
"listring[current_name;fuel]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 2)
end
local function can_dig(pos, player)
local inv = M(pos):get_inventory()
return inv:is_empty("fuel")
end
local function allow_metadata_inventory(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if Fuels[stack:get_name()] then
return stack:get_count()
end
return 0
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
if fields.update then
local mem = tubelib2.get_mem(pos)
M(pos):set_string("formspec", formspec(mem))
end
end
local function on_rightclick(pos, node, clicker)
local mem = tubelib2.get_mem(pos)
M(pos):set_string("formspec", formspec(mem))
end
local function swap_node(pos, name)
local node = minetest.get_node(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function get_fuel(pos)
local inv = M(pos):get_inventory()
local items = inv:get_stack("fuel", 1)
if items:get_count() > 0 then
local taken = items:take_item(1)
inv:set_stack("fuel", 1, items)
return taken
end
end
local function node_timer(pos, elapsed)
local mem = tubelib2.get_mem(pos)
if mem.running then
local this = TP({x=pos.x, y=pos.y+1, z=pos.z})
if this and this.trigger_boiler then
this.trigger_boiler({x=pos.x, y=pos.y+1, z=pos.z})
end
mem.burn_cycles = (mem.burn_cycles or 0) - 1
if mem.burn_cycles <= 0 then
if get_fuel(pos) then
mem.burn_cycles = BURN_CYCLES
else
mem.running = false
swap_node(pos, "techage:firebox")
M(pos):set_string("formspec", formspec(mem))
return false
end
end
return true
end
end
minetest.register_node("techage:firebox", {
description = I("TA2 Firebox"),
tiles = {
-- up, down, right, left, back, front
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_appl_firehole.png^techage_frame_ta2.png",
},
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
on_timer = node_timer,
can_dig = can_dig,
allow_metadata_inventory_put = allow_metadata_inventory,
allow_metadata_inventory_take = allow_metadata_inventory,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_construct = function(pos)
local mem = tubelib2.init_mem(pos)
mem.running = false
mem.burn_cycles = 0
local meta = M(pos)
meta:set_string("formspec", formspec(mem))
local inv = meta:get_inventory()
inv:set_size('fuel', 1)
end,
on_metadata_inventory_put = function(pos)
local mem = tubelib2.init_mem(pos)
mem.running = true
-- activate the formspec fire temporarily
mem.burn_cycles = BURN_CYCLES
M(pos):set_string("formspec", formspec(mem))
mem.burn_cycles = 0
swap_node(pos, "techage:firebox_on")
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})
minetest.register_node("techage:firebox_on", {
description = I("TA2 Firebox"),
tiles = {
-- up, down, right, left, back, front
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_frame_ta2.png",
"techage_firebox.png^techage_frame_ta2.png",
{
image = "techage_firebox4.png^techage_appl_firehole4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
},
paramtype2 = "facedir",
light_source = 8,
on_rotate = screwdriver.disallow,
groups = {cracky=2, not_in_creative_inventory=1},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
drop = "techage:firebox",
on_timer = node_timer,
can_dig = can_dig,
allow_metadata_inventory_put = allow_metadata_inventory,
allow_metadata_inventory_take = allow_metadata_inventory,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
})

180
steam_engine/flywheel.lua Normal file
View File

@ -0,0 +1,180 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
TA2 Steam Engine Flywheel
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local CYCLE_TIME = 10
local POWER = 8
local function swap_node(pos, name)
local node = minetest.get_node(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function formspec(mem)
return "size[8,7]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"image[3,0.5;1,2;"..techage.generator_formspec_level(mem)..
"button[5.5,1.2;1.8,1;update;"..I("Update").."]"..
"list[current_player;main;0,3;8,4;]"..
"listring[current_name;water]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 3)
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
if fields.update then
local mem = tubelib2.get_mem(pos)
M(pos):set_string("formspec", formspec(mem))
end
end
local function on_rightclick(pos, node, clicker)
local mem = tubelib2.get_mem(pos)
M(pos):set_string("formspec", formspec(mem))
end
local function node_timer(pos, elapsed)
local mem = tubelib2.get_mem(pos)
techage.generator_on(pos, POWER, techage.Axle)
return true
end
local function on_punch(pos, node, puncher, pointed_thing)
local mem = tubelib2.get_mem(pos)
if mem.power_produce and mem.power_produce > 0 then
swap_node(pos, "techage:flywheel")
techage.generator_off(pos, techage.Axle)
--techage.generator_off(pos)
minetest.get_node_timer(pos):stop()
else
swap_node(pos, "techage:flywheel_on")
techage.generator_on(pos, POWER, techage.Axle)
--techage.generator_on(pos, POWER)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end
end
minetest.register_node("techage:flywheel", {
description = I("TA2 Flywheel"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_axle_clutch.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_appl_open.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_flywheel.png",
"techage_filling_ta2.png^techage_frame_ta2.png^techage_flywheel.png^[transformFX]",
},
techage = {
network = techage.Axle,
power_consumption = techage.generator_power_consumption,
},
after_place_node = techage.generator_after_place_node,
after_tube_update = techage.generator_after_tube_update,
on_destruct = techage.generator_on_destruct,
after_dig_node = techage.generator_after_dig_node,
on_timer = node_timer,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_punch = on_punch,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:flywheel_on", {
description = I("TA2 Flywheel"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta2.png^techage_frame_ta2.png",
"techage_filling_ta2.png^techage_frame_ta2.png",
{
image = "techage_filling4_ta2.png^techage_axle_clutch4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
"techage_filling_ta2.png^techage_appl_open.png^techage_frame_ta2.png",
{
image = "techage_filling4_ta2.png^techage_frame4_ta2.png^techage_flywheel4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
{
image = "techage_filling4_ta2.png^techage_frame4_ta2.png^techage_flywheel4.png^[transformFX]",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
},
techage = {
network = techage.Axle,
power_consumption = techage.generator_power_consumption,
},
after_place_node = techage.generator_after_place_node,
after_tube_update = techage.generator_after_tube_update,
on_destruct = techage.generator_on_destruct,
after_dig_node = techage.generator_after_dig_node,
on_timer = node_timer,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_punch = on_punch,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2, not_in_creative_inventory=1},
--diggable = false,
--drop = "techage:flywheel",
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})

100
steam_engine/gearbox.lua Normal file
View File

@ -0,0 +1,100 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
TA2 Gearbox
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local POWER_CONSUME = 1
local function swap_node(pos, name)
local node = minetest.get_node(pos)
if node.name == name then
return
end
node.name = name
minetest.swap_node(pos, node)
end
local function turn_on(pos, dir, on)
if on then
swap_node(pos, "techage:gearbox_on")
else
swap_node(pos, "techage:gearbox")
end
end
minetest.register_node("techage:gearbox", {
description = "TA2 Gearbox",
tiles = {"techage_filling_ta2.png^techage_axle_gearbox.png^techage_frame_ta2.png"},
techage = {
turn_on = turn_on,
power_consumption = techage.distributor_power_consumption,
network = techage.Axle,
power_consume = POWER_CONSUME,
},
after_place_node = techage.distributor_after_place_node,
after_tube_update = techage.distributor_after_tube_update,
on_destruct = techage.distributor_on_destruct,
after_dig_node = techage.distributor_after_dig_node,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
minetest.register_node("techage:gearbox_on", {
tiles = {
-- up, down, right, left, back, front
{
image = "techage_filling4_ta2.png^techage_axle_gearbox4.png^techage_frame4_ta2.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.6,
},
},
},
techage = {
turn_on = turn_on,
power_consumption = techage.distributor_power_consumption,
network = techage.Axle,
power_consume = POWER_CONSUME,
},
after_place_node = techage.distributor_after_place_node,
after_tube_update = techage.distributor_after_tube_update,
on_destruct = techage.distributor_on_destruct,
after_dig_node = techage.distributor_after_dig_node,
paramtype2 = "facedir",
groups = {not_in_creative_inventory=1},
diggable = false,
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})

114
steam_engine/steam_pipe.lua Normal file
View File

@ -0,0 +1,114 @@
--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
TA2 Steam pipes for the Steam Engine
]]--
-- for lazy programmers
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local P = minetest.string_to_pos
local M = minetest.get_meta
-- Load support for intllib.
local MP = minetest.get_modpath("tubelib2")
local I,_ = dofile(MP.."/intllib.lua")
local Pipe = tubelib2.Tube:new({
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 1000,
show_infotext = false,
primary_node_names = {"techage:steam_pipeS", "techage:steam_pipeA"},
secondary_node_names = {"techage:cylinder", "techage:boiler2"},
after_place_tube = function(pos, param2, tube_type, num_tubes)
minetest.swap_node(pos, {name = "techage:steam_pipe"..tube_type, param2 = param2})
end,
})
Pipe:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir)
minetest.registered_nodes[node.name].after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir)
end)
techage.SteamPipe = Pipe
minetest.register_node("techage:steam_pipeS", {
description = I("TA2 Steam Pipe"),
tiles = {
"techage_steam_pipe.png^[transformR90",
"techage_steam_pipe.png^[transformR90",
"techage_steam_pipe.png",
"techage_steam_pipe.png",
"techage_steam_hole.png",
"techage_steam_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Pipe:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_tube(pos, oldnode)
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-1/8, -1/8, -4/8, 1/8, 1/8, 4/8},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly=3, cracky=3, snappy=3},
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:steam_pipeA", {
description = I("TA2 Steam Pipe"),
tiles = {
"techage_steam_knee2.png",
"techage_steam_hole2.png^[transformR180",
"techage_steam_knee.png^[transformR270",
"techage_steam_knee.png",
"techage_steam_knee2.png",
"techage_steam_hole2.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_tube(pos, oldnode)
end,
paramtype2 = "facedir", -- important!
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-1/8, -4/8, -1/8, 1/8, 1/8, 1/8},
{-1/8, -1/8, -4/8, 1/8, 1/8, -1/8},
},
},
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
sunlight_propagates = true,
is_ground_content = false,
groups = {crumbly=3, cracky=3, snappy=3, not_in_creative_inventory=1},
sounds = default.node_sound_metal_defaults(),
drop = "techage:steam_pipeS",
})

16
textures/shrink.py Normal file
View File

@ -0,0 +1,16 @@
import os, fnmatch
print ">>> Convert"
for filename in os.listdir("./"):
if fnmatch.fnmatch(filename, "*.png"):
print(filename)
os.system("pngquant --skip-if-larger --quality=8-16 --output ./%s.new ./%s" % (filename, filename))
print "\n>>> Copy"
for filename in os.listdir("./"):
if fnmatch.fnmatch(filename, "*.new"):
print(filename)
os.remove("./" + filename[:-4])
os.rename("./" + filename, "./" + filename[:-4])

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

BIN
textures/techage_axle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
textures/techage_axle4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
textures/techage_axle4R.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
textures/techage_axleR.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
textures/techage_boiler.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Some files were not shown because too many files have changed in this diff Show More