Cake+cauldron+endportalfr. put signal 4 comparator
[MineClone/MineClone2.git] / mods / ITEMS / REDSTONE / mcl_comparators / init.lua
blobc25793f3d1516555ab1ac50a3610049889dd1e41
1 -- Functions that get the input/output rules of the comparator
3 local comparator_get_output_rules = function(node)
4 local rules = {{x = -1, y = 0, z = 0, spread=true}}
5 for i = 0, node.param2 do
6 rules = mesecon.rotate_rules_left(rules)
7 end
8 return rules
9 end
12 local comparator_get_input_rules = function(node)
13 local rules = {
14 -- we rely on this order in update_self below
15 {x = 1, y = 0, z = 0}, -- back
16 {x = 0, y = 0, z = -1}, -- side
17 {x = 0, y = 0, z = 1}, -- side
19 for i = 0, node.param2 do
20 rules = mesecon.rotate_rules_left(rules)
21 end
22 return rules
23 end
26 -- Functions that are called after the delay time
28 local comparator_turnon = function(params)
29 local rules = comparator_get_output_rules(params.node)
30 mesecon.receptor_on(params.pos, rules)
31 end
34 local comparator_turnoff = function(params)
35 local rules = comparator_get_output_rules(params.node)
36 mesecon.receptor_off(params.pos, rules)
37 end
40 -- Functions that set the correct node type an schedule a turnon/off
42 local comparator_activate = function(pos, node)
43 local def = minetest.registered_nodes[node.name]
44 minetest.swap_node(pos, { name = def.comparator_onstate, param2 = node.param2 })
45 minetest.after(0.1, comparator_turnon , {pos = pos, node = node})
46 end
49 local comparator_deactivate = function(pos, node)
50 local def = minetest.registered_nodes[node.name]
51 minetest.swap_node(pos, { name = def.comparator_offstate, param2 = node.param2 })
52 minetest.after(0.1, comparator_turnoff, {pos = pos, node = node})
53 end
56 -- weather pos has an inventory that contains at least one item
57 local container_inventory_nonempty = function(pos)
58 local invnode = minetest.get_node(pos)
59 local invnodedef = minetest.registered_nodes[invnode.name]
60 -- Ignore stale nodes
61 if not invnodedef then return false end
63 -- Only accept containers. When a container is dug, it's inventory
64 -- seems to stay. and we don't want to accept the inventory of an air
65 -- block
66 if not invnodedef.groups.container then return false end
68 local inv = minetest.get_inventory({type="node", pos=pos})
69 if not inv then return false end
71 for listname, _ in pairs(inv:get_lists()) do
72 if not inv:is_empty(listname) then return true end
73 end
75 return false
76 end
78 -- weather pos has an constant signal output for the comparator
79 local static_signal_output = function(pos)
80 local node = minetest.get_node(pos)
81 local g = minetest.get_item_group(node.name, "comparator_signal")
82 return g > 0
83 end
85 -- whether the comparator should be on according to its inputs
86 local comparator_desired_on = function(pos, node)
87 local my_input_rules = comparator_get_input_rules(node);
88 local back_rule = my_input_rules[1]
89 local state
90 if back_rule then
91 local back_pos = vector.add(pos, back_rule)
92 state = mesecon.is_power_on(back_pos) or container_inventory_nonempty(back_pos) or static_signal_output(back_pos)
93 end
95 -- if back input if off, we don't need to check side inputs
96 if not state then return false end
98 -- without power levels, side inputs have no influence on output in compare
99 -- mode
100 local mode = minetest.registered_nodes[node.name].comparator_mode
101 if mode == "comp" then return state end
103 -- subtract mode, subtract max(side_inputs) from back input
104 local side_state = false
105 for ri = 2,3 do
106 if my_input_rules[ri] then
107 side_state = mesecon.is_power_on(vector.add(pos, my_input_rules[ri]))
109 if side_state then break end
111 -- state is known to be true
112 return not side_state
116 -- update comparator state, if needed
117 local update_self = function(pos, node)
118 node = node or minetest.get_node(pos)
119 local old_state = mesecon.is_receptor_on(node.name)
120 local new_state = comparator_desired_on(pos, node)
121 if new_state ~= old_state then
122 if new_state then
123 comparator_activate(pos, node)
124 else
125 comparator_deactivate(pos, node)
131 -- compute tile depending on state and mode
132 local get_tiles = function(state, mode)
133 local top = "mcl_comparators_"..state..".png^"..
134 "mcl_comparators_"..mode..".png"
135 local sides = "mcl_comparators_sides_"..state..".png^"..
136 "mcl_comparators_sides_"..mode..".png"
137 local ends = "mcl_comparators_ends_"..state..".png^"..
138 "mcl_comparators_ends_"..mode..".png"
139 return {
140 top, "mcl_stairs_stone_slab_top.png",
141 sides, sides.."^[transformFX",
142 ends, ends,
146 -- Given one mode, get the other mode
147 local flipmode = function(mode)
148 if mode == "comp" then return "sub"
149 elseif mode == "sub" then return "comp"
153 local make_rightclick_handler = function(state, mode)
154 local newnodename =
155 "mcl_comparators:comparator_"..state.."_"..flipmode(mode)
156 return function (pos, node)
157 minetest.swap_node(pos, {name = newnodename, param2 = node.param2 })
162 -- Register the 2 (states) x 2 (modes) comparators
164 local icon = "mcl_comparators_item.png"
166 local node_boxes = {
167 comp = {
168 { -8/16, -8/16, -8/16,
169 8/16, -6/16, 8/16 }, -- the main slab
170 { -1/16, -6/16, 6/16,
171 1/16, -4/16, 4/16 }, -- front torch
172 { -4/16, -6/16, -5/16,
173 -2/16, -1/16, -3/16 }, -- left back torch
174 { 2/16, -6/16, -5/16,
175 4/16, -1/16, -3/16 }, -- right back torch
177 sub = {
178 { -8/16, -8/16, -8/16,
179 8/16, -6/16, 8/16 }, -- the main slab
180 { -1/16, -6/16, 6/16,
181 1/16, -3/16, 4/16 }, -- front torch (active)
182 { -4/16, -6/16, -5/16,
183 -2/16, -1/16, -3/16 }, -- left back torch
184 { 2/16, -6/16, -5/16,
185 4/16, -1/16, -3/16 }, -- right back torch
189 local collision_box = {
190 type = "fixed",
191 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
194 local state_strs = {
195 [ mesecon.state.on ] = "on",
196 [ mesecon.state.off ] = "off",
199 local groups = {
200 dig_immediate = 3,
201 dig_by_water = 1,
202 destroy_by_lava_flow = 1,
203 dig_by_piston = 1,
204 attached_node = 1,
207 local on_rotate
208 if minetest.get_modpath("screwdriver") then
209 on_rotate = screwdriver.disallow
212 for _, mode in pairs{"comp", "sub"} do
213 for _, state in pairs{mesecon.state.on, mesecon.state.off} do
214 local state_str = state_strs[state]
215 local nodename =
216 "mcl_comparators:comparator_"..state_strs[state].."_"..mode
218 -- Help
219 local longdesc, usagehelp, use_help
220 if state_strs[state] == "off" and mode == "comp" then
221 longdesc = "Redstone comparators are multi-purpose redstone components. "..
222 "They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals."
224 usagehelp = "A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in "..
225 "arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.".."\n"..
226 "The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like chest) is placed in front of it and the container contains at least one item."..
227 "The side inputs are only powered by normal redstone power."..
228 "The redstone can operate in two modes: Transmission mode and subtraction mode. It "..
229 "starts in transmission mode and the mode can be changed by a rightclick.".."\n\n"..
230 "Transmission mode:"..
231 "The front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.".."\n"..
232 "Subtraction mode:"..
233 "The front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered."
234 else
235 use_help = false
238 local nodedef = {
239 description = "Redstone Comparator",
240 inventory_image = icon,
241 wield_image = icon,
242 _doc_items_create_entry = use_help,
243 _doc_items_longdesc = longdesc,
244 _doc_items_usagehelp = usagehelp,
245 drawtype = "nodebox",
246 tiles = get_tiles(state_strs[state], mode),
247 wield_image = "mcl_comparators_off.png",
248 walkable = true,
249 selection_box = collision_box,
250 collision_box = collision_box,
251 node_box = {
252 type = "fixed",
253 fixed = node_boxes[mode],
255 groups = groups,
256 paramtype = "light",
257 paramtype2 = "facedir",
258 sunlight_propagates = false,
259 is_ground_content = false,
260 drop = 'mcl_comparators:comparator_off_comp',
261 on_construct = update_self,
262 on_rightclick =
263 make_rightclick_handler(state_strs[state], mode),
264 comparator_mode = mode,
265 comparator_onstate = "mcl_comparators:comparator_on_"..mode,
266 comparator_offstate = "mcl_comparators:comparator_off_"..mode,
267 sounds = mcl_sounds.node_sound_stone_defaults(),
268 mesecons = {
269 receptor = {
270 state = state,
271 rules = comparator_get_output_rules,
273 effector = {
274 rules = comparator_get_input_rules,
275 action_change = update_self,
278 on_rotate = on_rotate,
281 if mode == "comp" and state == mesecon.state.off then
282 -- This is the prototype
283 nodedef._doc_items_create_entry = true
284 else
285 nodedef.groups = table.copy(nodedef.groups)
286 nodedef.groups.not_in_creative_inventory = 1
287 local extra_desc = {}
288 if mode == "sub" then
289 table.insert(extra_desc, "Subtract")
291 if state == mesecon.state.on then
292 table.insert(extra_desc, "Powered")
294 nodedef.description = nodedef.description..
295 " ("..table.concat(extra_desc, ", ")..")"
298 minetest.register_node(nodename, nodedef)
302 -- Register recipies
303 local rstorch = "mesecons_torch:mesecon_torch_on"
304 local quartz = "mcl_nether:quartz"
305 local stone = "mcl_core:stone"
307 minetest.register_craft({
308 output = "mcl_comparators:comparator_off_comp",
309 recipe = {
310 { "", rstorch, "" },
311 { rstorch, quartz, rstorch },
312 { stone, stone, stone },
316 -- Register active block handlers
317 minetest.register_abm({
318 label = "Comparator signal input check (comparator is off)",
319 nodenames = {
320 "mcl_comparators:comparator_off_comp",
321 "mcl_comparators:comparator_off_sub",
323 neighbors = {"group:container", "group:comparator_signal"},
324 interval = 1,
325 chance = 1,
326 action = update_self,
329 minetest.register_abm({
330 label = "Comparator signal input check (comparator is on)",
331 nodenames = {
332 "mcl_comparators:comparator_on_comp",
333 "mcl_comparators:comparator_on_sub",
335 -- needs to run regardless of neighbors to make sure we detect when a
336 -- container is dug
337 interval = 1,
338 chance = 1,
339 action = update_self,
343 -- Add entry aliases for the Help
344 if minetest.get_modpath("doc") then
345 doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
346 "nodes", "mcl_comparators:comparator_off_sub")
347 doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
348 "nodes", "mcl_comparators:comparator_on_comp")
349 doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
350 "nodes", "mcl_comparators:comparator_on_sub")