summaryrefslogtreecommitdiff
path: root/new_flow_logic/abms.lua
blob: 640493a2f992af20558332ed9db835200fa20031 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
-- reimplementation of new_flow_logic branch: processing functions
-- written 2017 by thetaepsilon



local flowlogic = {}
flowlogic.helpers = {}
pipeworks.flowlogic = flowlogic



-- borrowed from above: might be useable to replace the above coords tables
local make_coords_offsets = function(pos, include_base)
	local coords = {
		{x=pos.x,y=pos.y-1,z=pos.z},
		{x=pos.x,y=pos.y+1,z=pos.z},
		{x=pos.x-1,y=pos.y,z=pos.z},
		{x=pos.x+1,y=pos.y,z=pos.z},
		{x=pos.x,y=pos.y,z=pos.z-1},
		{x=pos.x,y=pos.y,z=pos.z+1},
	}
	if include_base then table.insert(coords, pos) end
	return coords
end



-- local debuglog = function(msg) print("## "..msg) end



-- new version of liquid check
-- accepts a limit parameter to only delete water blocks that the receptacle can accept,
-- and returns it so that the receptacle can update it's pressure values.
local check_for_liquids_v2 = function(pos, limit)
	local coords = make_coords_offsets(pos, false)
	local total = 0
	for index, tpos in ipairs(coords) do
		if total >= limit then break end
		local name = minetest.get_node(tpos).name
		if name == "default:water_source" then
			minetest.remove_node(tpos)
			total = total + 1
		end
	end
	return total
end
flowlogic.check_for_liquids_v2 = check_for_liquids_v2



local label_pressure = "pipeworks.water_pressure"
local label_haspressure = "pipeworks.is_pressure_node"
flowlogic.balance_pressure = function(pos, node)
	-- debuglog("balance_pressure() "..node.name.." at "..pos.x.." "..pos.y.." "..pos.z)
	-- check the pressure of all nearby nodes, and average it out.
	-- for the moment, only balance neighbour nodes if it already has a pressure value.
	-- XXX: maybe this could be used to add fluid behaviour to other mod's nodes too?

	-- unconditionally include self in nodes to average over
	local meta = minetest.get_meta(pos)
	local currentpressure = meta:get_float(label_pressure)
	meta:set_int(label_haspressure, 1)
	local connections = { meta }
	local totalv = currentpressure
	local totalc = 1

	-- then handle neighbours, but if not a pressure node don't consider them at all
	for _, npos in ipairs(make_coords_offsets(pos, false)) do
		local neighbour = minetest.get_meta(npos)
		local haspressure = (neighbour:get_int(label_haspressure) ~= 0)
		if haspressure then
			local n = neighbour:get_float(label_pressure)
			table.insert(connections, neighbour)
			totalv = totalv + n
			totalc = totalc + 1
		end
	end

	local average = totalv / totalc
	for _, targetmeta in ipairs(connections) do
		targetmeta:set_float(label_pressure, average)
	end
end



flowlogic.run_input = function(pos, node, maxpressure, intakefn)
	-- intakefn allows a given input node to define it's own intake logic.
	-- this function will calculate the maximum amount of water that can be taken in;
	-- the intakefn will be given this and is expected to return the actual absorption amount.

	local meta = minetest.get_meta(pos)
	local currentpressure = meta:get_float(label_pressure)
	local intake_limit = maxpressure - currentpressure
	if intake_limit <= 0 then return end

	local actual_intake = intakefn(pos, intake_limit)
	if actual_intake <= 0 then return end
	if actual_intake >= intake_limit then actual_intake = intake_limit end

	local newpressure = actual_intake + currentpressure
	-- debuglog("oldpressure "..currentpressure.." intake_limit "..intake_limit.." actual_intake "..actual_intake.." newpressure "..newpressure)
	meta:set_float(label_pressure, newpressure)
end



-- flowlogic output helper for spigots
-- tries to place a water block in the world beneath the spigot.
-- threshold checking is assumed to be handled by the node registration;
-- see register_local_pipes.lua for the pipeworks default spigot.
flowlogic.helpers.output_spigot = function(pos, node, currentpressure)
	local taken = 0
	local below = {x=pos.x, y=pos.y-1, z=pos.z}
	local name = minetest.get_node(below).name
	if (name == "air") or (name == "default:water_flowing") then
		minetest.set_node(below, {name="default:water_source"})
		taken = taken + 1
	end
	return taken
end



flowlogic.run_output = function(pos, node, threshold, outputfn)
	-- callback for output devices.
	-- takes care of checking a minimum pressure value and updating the node metadata.
	-- the outputfn is provided the current pressure and returns the pressure "taken".
	-- as an example, using this with the above spigot function,
	-- the spigot function tries to output a water source if it will fit in the world.
	local meta = minetest.get_meta(pos)
	-- sometimes I wonder if meta:get_* returning default values would ever be problematic.
	-- though here it doesn't matter, an uninit'd node returns 0, which is fine for a new, empty node.
	local currentpressure = meta:get_float(label_pressure)
	if currentpressure > threshold then
		local takenpressure = outputfn(pos, node, currentpressure)
		local newpressure = currentpressure - takenpressure
		if newpressure < 0 then currentpressure = 0 end
		meta:set_float(label_pressure, newpressure)
	end
end



flowlogic.run_spigot_output = function(pos, node)
	-- try to output a water source node if there's enough pressure and space below.
	local meta = minetest.get_meta(pos)
	local currentpressure = meta:get_float(label_pressure)
	if currentpressure > 1 then
		local below = {x=pos.x, y=pos.y-1, z=pos.z}
		local name = minetest.get_node(below).name
		if (name == "air") or (name == "default:water_flowing") then
			minetest.set_node(below, {name="default:water_source"})
			meta:set_float(label_pressure, currentpressure - 1)
		end
	end
end