mods that hopefully work for a TechAge-based pack
This commit is contained in:
1 parent
4e6b08d194
commit
c27db2a537
6234 files changed
+375578
No files matched your search
@@ -0,0 +1,561 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
A state model/class for TechAge nodes.
|
||||
|
||||
]]--
|
||||
|
||||
|
||||
--[[
|
||||
|
||||
Node states:
|
||||
|
||||
+-----------------------------------+ +------------+
|
||||
| | | |
|
||||
| V V |
|
||||
| +---------+ |
|
||||
| | | |
|
||||
| +---------| STOPPED | |
|
||||
| | | | |
|
||||
| button | +---------+ |
|
||||
| | ^ |
|
||||
button | V | button |
|
||||
| +---------+ | | button
|
||||
| +--------->| |---------+ |
|
||||
| | power | RUNNING | |
|
||||
| | +------| |---------+ |
|
||||
| | | +---------+ | |
|
||||
| | | ^ | | |
|
||||
| | | | | | |
|
||||
| | V | V V |
|
||||
| +---------+ +----------+ +---------+ |
|
||||
| | | | | | | |
|
||||
+---| NOPOWER | | STANDBY/ | | FAULT |----------+
|
||||
| | | BLOCKED | | |
|
||||
+---------+ +----------+ +---------+
|
||||
|
||||
|
||||
| cycle time operational needs power
|
||||
+---------+------------+-------------+-------------
|
||||
| RUNNING normal yes yes
|
||||
| BLOCKED long yes no
|
||||
| STANDBY long yes no
|
||||
| NOPOWER long no no
|
||||
| FAULT none no no
|
||||
| STOPPED none no no
|
||||
|
||||
Node nvm data:
|
||||
"techage_state" - node state, like "RUNNING"
|
||||
"techage_countdown" - countdown to standby mode
|
||||
]]--
|
||||
|
||||
-- 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 = techage.get_node_lvm
|
||||
|
||||
local MAX_CYCLE_TIME = 20
|
||||
|
||||
--
|
||||
-- TechAge machine states
|
||||
--
|
||||
|
||||
techage.RUNNING = 1 -- in normal operation/turned on
|
||||
techage.BLOCKED = 2 -- a pushing node is blocked due to a full destination inventory
|
||||
techage.STANDBY = 3 -- nothing to do (e.g. no input items), or node (world) not loaded
|
||||
techage.NOPOWER = 4 -- only for power consuming nodes, no operation
|
||||
techage.FAULT = 5 -- any fault state (e.g. wrong source items), which can be fixed by the player
|
||||
techage.STOPPED = 6 -- not operational/turned off
|
||||
techage.UNLOADED = 7 -- Map block unloaded
|
||||
techage.INACTIVE = 8 -- Map block loaded but node is not actively working
|
||||
|
||||
techage.StatesImg = {
|
||||
"techage_inv_button_on.png",
|
||||
"techage_inv_button_warning.png",
|
||||
"techage_inv_button_standby.png",
|
||||
"techage_inv_button_nopower.png",
|
||||
"techage_inv_button_error.png",
|
||||
"techage_inv_button_off.png",
|
||||
}
|
||||
|
||||
local function error(pos, msg)
|
||||
minetest.log("error", "[TA states] "..msg.." at "..S(pos).." "..N(pos).name)
|
||||
end
|
||||
|
||||
-- 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 "techage_inv_button_off.png"
|
||||
end
|
||||
|
||||
function techage.get_power_image(pos, nvm)
|
||||
local node = techage.get_node_lvm(pos)
|
||||
local s = "3" -- electrical power
|
||||
if string.find(node.name, "techage:ta2") then
|
||||
s = "2" -- axles power
|
||||
end
|
||||
return "techage_inv_powerT"..s..".png"
|
||||
end
|
||||
|
||||
-- State string based on button states
|
||||
techage.StateStrings = {"running", "blocked", "standby", "nopower", "fault", "stopped"}
|
||||
|
||||
--
|
||||
-- Local States
|
||||
--
|
||||
local RUNNING = techage.RUNNING
|
||||
local BLOCKED = techage.BLOCKED
|
||||
local STANDBY = techage.STANDBY
|
||||
local NOPOWER = techage.NOPOWER
|
||||
local FAULT = techage.FAULT
|
||||
local STOPPED = techage.STOPPED
|
||||
|
||||
|
||||
--
|
||||
-- NodeStates Class Functions
|
||||
--
|
||||
techage.NodeStates = {}
|
||||
local NodeStates = techage.NodeStates
|
||||
|
||||
local function can_start(pos, nvm)
|
||||
--if false, node goes in FAULT
|
||||
return true
|
||||
end
|
||||
|
||||
local function has_power(pos, nvm)
|
||||
--if false, node goes in NOPOWER
|
||||
return true
|
||||
end
|
||||
|
||||
local function swap_node(pos, new_name, old_name)
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == new_name then
|
||||
return
|
||||
end
|
||||
if node.name == old_name then
|
||||
node.name = new_name
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
-- true if node_timer should be executed
|
||||
function techage.is_operational(nvm)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
return state < NOPOWER
|
||||
end
|
||||
|
||||
function techage.is_running(nvm)
|
||||
return (nvm.techage_state or STOPPED) == RUNNING
|
||||
end
|
||||
|
||||
-- consumes power
|
||||
function techage.needs_power(nvm)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
return state == RUNNING or state == NOPOWER
|
||||
end
|
||||
|
||||
-- consumes power
|
||||
function techage.needs_power2(state)
|
||||
state = state or STOPPED
|
||||
return state == RUNNING or state == NOPOWER
|
||||
end
|
||||
|
||||
function techage.get_state_string(nvm)
|
||||
return techage.StateStrings[nvm.techage_state or STOPPED]
|
||||
end
|
||||
|
||||
function NodeStates:new(attr)
|
||||
local o = {
|
||||
-- mandatory
|
||||
cycle_time = attr.cycle_time, -- for running state
|
||||
standby_ticks = attr.standby_ticks, -- for standby state
|
||||
-- optional
|
||||
countdown_ticks = attr.countdown_ticks or 1,
|
||||
node_name_passive = attr.node_name_passive,
|
||||
node_name_active = attr.node_name_active,
|
||||
infotext_name = attr.infotext_name,
|
||||
has_power = attr.has_power or has_power,
|
||||
can_start = attr.can_start or can_start,
|
||||
start_node = attr.start_node,
|
||||
stop_node = attr.stop_node,
|
||||
formspec_func = attr.formspec_func,
|
||||
on_state_change = attr.on_state_change,
|
||||
quick_start = attr.quick_start,
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function NodeStates:node_init(pos, nvm, number)
|
||||
nvm.techage_state = STOPPED
|
||||
M(pos):set_string("node_number", number)
|
||||
if self.infotext_name then
|
||||
M(pos):set_string("infotext", self.infotext_name.." "..number..": stopped")
|
||||
end
|
||||
if self.formspec_func then
|
||||
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm) or "")
|
||||
end
|
||||
end
|
||||
|
||||
-- to be used to re-start the timer outside of node_timer()
|
||||
local function start_timer_delayed(pos, cycle_time)
|
||||
local t = minetest.get_node_timer(pos)
|
||||
t:stop()
|
||||
if cycle_time > 0.9 then
|
||||
minetest.after(0.1, t.start, t, cycle_time)
|
||||
else
|
||||
error(pos, "invalid cycle_time")
|
||||
end
|
||||
end
|
||||
|
||||
function NodeStates:stop(pos, nvm)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
nvm.techage_state = STOPPED
|
||||
if self.stop_node then
|
||||
self.stop_node(pos, nvm, state)
|
||||
end
|
||||
if self.node_name_passive then
|
||||
swap_node(pos, self.node_name_passive, self.node_name_active)
|
||||
end
|
||||
if self.infotext_name then
|
||||
local number = M(pos):get_string("node_number")
|
||||
M(pos):set_string("infotext", self.infotext_name.." "..number..": stopped")
|
||||
end
|
||||
if self.formspec_func then
|
||||
nvm.ta_state_tooltip = "stopped"
|
||||
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm) or "")
|
||||
end
|
||||
if self.on_state_change then
|
||||
self.on_state_change(pos, state, STOPPED)
|
||||
end
|
||||
if minetest.get_node_timer(pos):is_started() then
|
||||
minetest.get_node_timer(pos):stop()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function NodeStates:start(pos, nvm)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
if state ~= RUNNING and state ~= FAULT then
|
||||
local res = self.can_start(pos, nvm, state)
|
||||
if res ~= true then
|
||||
self:fault(pos, nvm, res)
|
||||
return false
|
||||
end
|
||||
if not self.has_power(pos, nvm, state) then
|
||||
self:nopower(pos, nvm)
|
||||
return false
|
||||
end
|
||||
nvm.techage_state = RUNNING
|
||||
if self.start_node then
|
||||
self.start_node(pos, nvm, state)
|
||||
end
|
||||
nvm.techage_countdown = self.countdown_ticks
|
||||
if self.node_name_active then
|
||||
swap_node(pos, self.node_name_active, self.node_name_passive)
|
||||
end
|
||||
if self.infotext_name then
|
||||
local number = M(pos):get_string("node_number")
|
||||
M(pos):set_string("infotext", self.infotext_name.." "..number..": running")
|
||||
end
|
||||
if self.formspec_func then
|
||||
nvm.ta_state_tooltip = "running"
|
||||
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm) or "")
|
||||
end
|
||||
if minetest.get_node_timer(pos):is_started() then
|
||||
minetest.get_node_timer(pos):stop()
|
||||
end
|
||||
if self.on_state_change then
|
||||
self.on_state_change(pos, state, RUNNING)
|
||||
end
|
||||
start_timer_delayed(pos, self.cycle_time)
|
||||
|
||||
if self.quick_start and state == STOPPED then
|
||||
self.quick_start(pos, 0)
|
||||
end
|
||||
self:trigger_state(pos, nvm)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function NodeStates:standby(pos, nvm, err_string)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
if state == RUNNING or state == BLOCKED then
|
||||
nvm.techage_state = STANDBY
|
||||
if self.node_name_passive then
|
||||
swap_node(pos, self.node_name_passive, self.node_name_active)
|
||||
end
|
||||
if self.infotext_name then
|
||||
local number = M(pos):get_string("node_number")
|
||||
M(pos):set_string("infotext", self.infotext_name.." "..number..": "..(err_string or "standby"))
|
||||
end
|
||||
if self.formspec_func then
|
||||
nvm.ta_state_tooltip = err_string or "standby"
|
||||
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm) or "")
|
||||
end
|
||||
if self.on_state_change then
|
||||
self.on_state_change(pos, state, STANDBY)
|
||||
end
|
||||
start_timer_delayed(pos, self.cycle_time * self.standby_ticks)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- special case of standby for pushing nodes
|
||||
function NodeStates:blocked(pos, nvm, err_string)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
if state == RUNNING then
|
||||
nvm.techage_state = BLOCKED
|
||||
if self.node_name_passive then
|
||||
swap_node(pos, self.node_name_passive, self.node_name_active)
|
||||
end
|
||||
if self.infotext_name then
|
||||
local number = M(pos):get_string("node_number")
|
||||
M(pos):set_string("infotext", self.infotext_name.." "..number..": "..(err_string or "blocked"))
|
||||
end
|
||||
if self.formspec_func then
|
||||
nvm.ta_state_tooltip = err_string or "blocked"
|
||||
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm) or "")
|
||||
end
|
||||
if self.on_state_change then
|
||||
self.on_state_change(pos, state, BLOCKED)
|
||||
end
|
||||
start_timer_delayed(pos, self.cycle_time * self.standby_ticks)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function NodeStates:nopower(pos, nvm, err_string)
|
||||
local state = nvm.techage_state or RUNNING
|
||||
if state ~= NOPOWER then
|
||||
nvm.techage_state = NOPOWER
|
||||
if self.node_name_passive then
|
||||
swap_node(pos, self.node_name_passive, self.node_name_active)
|
||||
end
|
||||
if self.infotext_name then
|
||||
local number = M(pos):get_string("node_number")
|
||||
M(pos):set_string("infotext", self.infotext_name.." "..number..": "..(err_string or "no power"))
|
||||
end
|
||||
if self.formspec_func then
|
||||
nvm.ta_state_tooltip = err_string or "no power"
|
||||
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm) or "")
|
||||
end
|
||||
if self.on_state_change then
|
||||
self.on_state_change(pos, state, NOPOWER)
|
||||
end
|
||||
start_timer_delayed(pos, self.cycle_time * self.standby_ticks)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function NodeStates:fault(pos, nvm, err_string)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
err_string = err_string or "fault"
|
||||
if state == RUNNING or state == STOPPED then
|
||||
nvm.techage_state = FAULT
|
||||
if self.node_name_passive then
|
||||
swap_node(pos, self.node_name_passive, self.node_name_active)
|
||||
end
|
||||
if self.infotext_name then
|
||||
local number = M(pos):get_string("node_number")
|
||||
M(pos):set_string("infotext", self.infotext_name.." "..number..": "..err_string)
|
||||
end
|
||||
if self.formspec_func then
|
||||
nvm.ta_state_tooltip = err_string or "fault"
|
||||
M(pos):set_string("formspec", self.formspec_func(self, pos, nvm) or "")
|
||||
end
|
||||
if self.on_state_change then
|
||||
self.on_state_change(pos, state, FAULT)
|
||||
end
|
||||
minetest.get_node_timer(pos):stop()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function NodeStates:get_state(nvm)
|
||||
return nvm.techage_state or techage.STOPPED
|
||||
end
|
||||
|
||||
-- keep the timer running?
|
||||
function NodeStates:is_active(nvm)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
return state < FAULT
|
||||
end
|
||||
|
||||
function NodeStates:start_if_standby(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if nvm.techage_state == STANDBY then
|
||||
self:start(pos, nvm)
|
||||
end
|
||||
end
|
||||
|
||||
-- To be called if node is idle.
|
||||
-- If countdown reaches zero, the node is set to STANDBY.
|
||||
function NodeStates:idle(pos, nvm)
|
||||
local countdown = (nvm.techage_countdown or 0) - 1
|
||||
nvm.techage_countdown = countdown
|
||||
if countdown <= 0 then
|
||||
self:standby(pos, nvm)
|
||||
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, nvm, val)
|
||||
-- set to RUNNING if not already done
|
||||
if nvm.techage_state ~= RUNNING then
|
||||
self:start(pos, nvm)
|
||||
end
|
||||
nvm.techage_countdown = val or 4
|
||||
nvm.last_active = minetest.get_gametime()
|
||||
end
|
||||
|
||||
function NodeStates:trigger_state(pos, nvm)
|
||||
nvm.last_active = minetest.get_gametime()
|
||||
end
|
||||
|
||||
-- Start/stop node based on button events.
|
||||
-- if function returns false, no button was pressed
|
||||
function NodeStates:state_button_event(pos, nvm, fields)
|
||||
if fields.state_button ~= nil then
|
||||
local state = nvm.techage_state or STOPPED
|
||||
if state == STOPPED or state == STANDBY or state == BLOCKED then
|
||||
if not self:start(pos, nvm) and (state == STANDBY or state == BLOCKED) then
|
||||
self:stop(pos, nvm)
|
||||
end
|
||||
elseif state == RUNNING or state == FAULT or state == NOPOWER then
|
||||
self:stop(pos, nvm)
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function NodeStates:get_state_button_image(nvm)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
return techage.state_button(state)
|
||||
end
|
||||
|
||||
function NodeStates:get_state_tooltip(nvm)
|
||||
local tp = nvm.ta_state_tooltip or ""
|
||||
return tp..";#0C3D32;#FFFFFF"
|
||||
end
|
||||
|
||||
-- command interface
|
||||
function NodeStates:on_receive_message(pos, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if topic == "on" then
|
||||
self:start(pos, techage.get_nvm(pos))
|
||||
return true
|
||||
elseif topic == "off" then
|
||||
self:stop(pos, techage.get_nvm(pos))
|
||||
return true
|
||||
elseif topic == "state" then
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name == "ignore" then -- unloaded node?
|
||||
return "unloaded"
|
||||
elseif nvm.techage_state == RUNNING then
|
||||
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
|
||||
if ttl < minetest.get_gametime() then
|
||||
return "inactive"
|
||||
end
|
||||
end
|
||||
return techage.get_state_string(techage.get_nvm(pos))
|
||||
elseif topic == "fuel" then
|
||||
return techage.fuel.get_fuel_amount(nvm)
|
||||
elseif topic == "load" then
|
||||
return techage.liquid.get_liquid_amount(nvm)
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end
|
||||
|
||||
function NodeStates:on_beduino_receive_cmnd(pos, topic, payload)
|
||||
if topic == 1 then
|
||||
if payload[1] == 0 then
|
||||
self:stop(pos, techage.get_nvm(pos))
|
||||
return 0
|
||||
else
|
||||
self:start(pos, techage.get_nvm(pos))
|
||||
return 0
|
||||
end
|
||||
else
|
||||
return 2 -- unknown or invalid topic
|
||||
end
|
||||
end
|
||||
|
||||
function NodeStates:on_beduino_request_data(pos, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if topic == 128 then
|
||||
return 0, techage.get_node_lvm(pos).name
|
||||
elseif topic == 129 then
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name == "ignore" then -- unloaded node?
|
||||
return 0, {techage.UNLOADED}
|
||||
elseif nvm.techage_state == RUNNING then
|
||||
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
|
||||
if ttl < minetest.get_gametime() then
|
||||
return 0, {techage.INACTIVE}
|
||||
end
|
||||
end
|
||||
return 0, {nvm.techage_state or STOPPED}
|
||||
else
|
||||
return 2, "" -- topic is unknown or invalid
|
||||
end
|
||||
end
|
||||
|
||||
function NodeStates.get_beduino_state(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if node.name == "ignore" then -- unloaded node?
|
||||
return 0, {techage.UNLOADED}
|
||||
elseif nvm.techage_state == RUNNING then
|
||||
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
|
||||
if ttl < minetest.get_gametime() then
|
||||
return 0, {techage.INACTIVE}
|
||||
end
|
||||
end
|
||||
return 0, {nvm.techage_state or STOPPED}
|
||||
end
|
||||
|
||||
-- restart timer
|
||||
function NodeStates:on_node_load(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local state = nvm.techage_state or STOPPED
|
||||
if state == RUNNING then
|
||||
minetest.get_node_timer(pos):start(self.cycle_time)
|
||||
elseif state < FAULT then
|
||||
minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("techage:defect_dummy", {
|
||||
description = "Corrupted Node (to be replaced)",
|
||||
tiles = {
|
||||
"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_defect.png",
|
||||
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_defect.png",
|
||||
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_defect.png",
|
||||
"techage_filling_ta2.png^techage_frame_ta2.png^techage_appl_defect.png",
|
||||
},
|
||||
drop = "",
|
||||
groups = {cracky=2, crumbly=2, choppy=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
})
|
||||
Reference in new issue
Block a user