Update help text of comparators
[MineClone/MineClone2.git] / mods / ITEMS / REDSTONE / mcl_comparators / init.lua
blobc36c2f181ce8965ad53a6be903725d4f0e129c0f
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 -- wether 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 -- whether the comparator should be on according to its inputs
79 local comparator_desired_on = function(pos, node)
80 local my_input_rules = comparator_get_input_rules(node);
81 local back_rule = my_input_rules[1]
82 local state
83 if back_rule then
84 state = mesecon.is_power_on(vector.add(pos, back_rule)) or container_inventory_nonempty(vector.add(pos, back_rule))
85 end
87 -- if back input if off, we don't need to check side inputs
88 if not state then return false end
90 -- without power levels, side inputs have no influence on output in compare
91 -- mode
92 local mode = minetest.registered_nodes[node.name].comparator_mode
93 if mode == "comp" then return state end
95 -- subtract mode, subtract max(side_inputs) from back input
96 local side_state = false
97 for ri = 2,3 do
98 if my_input_rules[ri] then
99 side_state = mesecon.is_power_on(vector.add(pos, my_input_rules[ri]))
101 if side_state then break end
103 -- state is known to be true
104 return not side_state
108 -- update comparator state, if needed
109 local update_self = function(pos, node)
110 node = node or minetest.get_node(pos)
111 local old_state = mesecon.is_receptor_on(node.name)
112 local new_state = comparator_desired_on(pos, node)
113 if new_state ~= old_state then
114 if new_state then
115 comparator_activate(pos, node)
116 else
117 comparator_deactivate(pos, node)
123 -- compute tile depending on state and mode
124 local get_tiles = function(state, mode)
125 local top = "mcl_comparators_"..state..".png^"..
126 "mcl_comparators_"..mode..".png"
127 local sides = "mcl_comparators_sides_"..state..".png^"..
128 "mcl_comparators_sides_"..mode..".png"
129 local ends = "mcl_comparators_ends_"..state..".png^"..
130 "mcl_comparators_ends_"..mode..".png"
131 return {
132 top, "mcl_stairs_stone_slab_top.png",
133 sides, sides.."^[transformFX",
134 ends, ends,
138 -- Given one mode, get the other mode
139 local flipmode = function(mode)
140 if mode == "comp" then return "sub"
141 elseif mode == "sub" then return "comp"
145 local make_rightclick_handler = function(state, mode)
146 local newnodename =
147 "mcl_comparators:comparator_"..state.."_"..flipmode(mode)
148 return function (pos, node)
149 minetest.swap_node(pos, {name = newnodename, param2 = node.param2 })
154 -- Register the 2 (states) x 2 (modes) comparators
156 local icon = "mcl_comparators_item.png"
158 local node_boxes = {
159 comp = {
160 { -8/16, -8/16, -8/16,
161 8/16, -6/16, 8/16 }, -- the main slab
162 { -1/16, -6/16, 6/16,
163 1/16, -4/16, 4/16 }, -- front torch
164 { -4/16, -6/16, -5/16,
165 -2/16, -1/16, -3/16 }, -- left back torch
166 { 2/16, -6/16, -5/16,
167 4/16, -1/16, -3/16 }, -- right back torch
169 sub = {
170 { -8/16, -8/16, -8/16,
171 8/16, -6/16, 8/16 }, -- the main slab
172 { -1/16, -6/16, 6/16,
173 1/16, -3/16, 4/16 }, -- front torch (active)
174 { -4/16, -6/16, -5/16,
175 -2/16, -1/16, -3/16 }, -- left back torch
176 { 2/16, -6/16, -5/16,
177 4/16, -1/16, -3/16 }, -- right back torch
181 local collision_box = {
182 type = "fixed",
183 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
186 local state_strs = {
187 [ mesecon.state.on ] = "on",
188 [ mesecon.state.off ] = "off",
191 local groups = {
192 dig_immediate = 3,
193 dig_by_water = 1,
194 destroy_by_lava_flow = 1,
195 dig_by_piston = 1,
196 attached_node = 1,
199 local on_rotate
200 if minetest.get_modpath("screwdriver") then
201 on_rotate = screwdriver.disallow
204 for _, mode in pairs{"comp", "sub"} do
205 for _, state in pairs{mesecon.state.on, mesecon.state.off} do
206 local state_str = state_strs[state]
207 local nodename =
208 "mcl_comparators:comparator_"..state_strs[state].."_"..mode
210 -- Help
211 local longdesc, usagehelp, use_help
212 if state_strs[state] == "off" and mode == "comp" then
213 longdesc = "Redstone comparators are multi-purpose redstone components. "..
214 "They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals."
216 usagehelp = "A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in "..
217 "arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.".."\n"..
218 "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."..
219 "The side inputs are only powered by normal redstone power."..
220 "The redstone can operate in two modes: Transmission mode and subtraction mode. It "..
221 "starts in transmission mode and the mode can be changed by a rightclick.".."\n\n"..
222 "Transmission mode:"..
223 "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"..
224 "Subtraction mode:"..
225 "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."
226 else
227 use_help = false
230 local nodedef = {
231 description = "Redstone Comparator",
232 inventory_image = icon,
233 wield_image = icon,
234 _doc_items_create_entry = use_help,
235 _doc_items_longdesc = longdesc,
236 _doc_items_usagehelp = usagehelp,
237 drawtype = "nodebox",
238 tiles = get_tiles(state_strs[state], mode),
239 wield_image = "mcl_comparators_off.png",
240 walkable = true,
241 selection_box = collision_box,
242 collision_box = collision_box,
243 node_box = {
244 type = "fixed",
245 fixed = node_boxes[mode],
247 groups = groups,
248 paramtype = "light",
249 paramtype2 = "facedir",
250 sunlight_propagates = false,
251 is_ground_content = false,
252 drop = 'mcl_comparators:comparator_off_comp',
253 on_construct = update_self,
254 on_rightclick =
255 make_rightclick_handler(state_strs[state], mode),
256 comparator_mode = mode,
257 comparator_onstate = "mcl_comparators:comparator_on_"..mode,
258 comparator_offstate = "mcl_comparators:comparator_off_"..mode,
259 sounds = mcl_sounds.node_sound_stone_defaults(),
260 mesecons = {
261 receptor = {
262 state = state,
263 rules = comparator_get_output_rules,
265 effector = {
266 rules = comparator_get_input_rules,
267 action_change = update_self,
270 on_rotate = on_rotate,
273 if mode == "comp" and state == mesecon.state.off then
274 -- This is the prototype
275 nodedef._doc_items_create_entry = true
276 else
277 nodedef.groups = table.copy(nodedef.groups)
278 nodedef.groups.not_in_creative_inventory = 1
279 local extra_desc = {}
280 if mode == "sub" then
281 table.insert(extra_desc, "Subtract")
283 if state == mesecon.state.on then
284 table.insert(extra_desc, "Powered")
286 nodedef.description = nodedef.description..
287 " ("..table.concat(extra_desc, ", ")..")"
290 minetest.register_node(nodename, nodedef)
294 -- Register recipies
295 local rstorch = "mesecons_torch:mesecon_torch_on"
296 local quartz = "mcl_nether:quartz"
297 local stone = "mcl_core:stone"
299 minetest.register_craft({
300 output = "mcl_comparators:comparator_off_comp",
301 recipe = {
302 { "", rstorch, "" },
303 { rstorch, quartz, rstorch },
304 { stone, stone, stone },
308 -- Register active block handlers
309 minetest.register_abm({
310 label = "Comparator check for containers",
311 nodenames = {
312 "mcl_comparators:comparator_off_comp",
313 "mcl_comparators:comparator_off_sub",
315 neighbors = {"group:container"},
316 interval = 1,
317 chance = 1,
318 action = update_self,
321 minetest.register_abm({
322 label = "Comparator check for no containers",
323 nodenames = {
324 "mcl_comparators:comparator_on_comp",
325 "mcl_comparators:comparator_on_sub",
327 -- needs to run regardless of neighbors to make sure we detect when a
328 -- container is dug
329 interval = 1,
330 chance = 1,
331 action = update_self,
335 -- Add entry aliases for the Help
336 if minetest.get_modpath("doc") then
337 doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
338 "nodes", "mcl_comparators:comparator_off_sub")
339 doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
340 "nodes", "mcl_comparators:comparator_on_comp")
341 doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
342 "nodes", "mcl_comparators:comparator_on_sub")