2 minetest,vector,math,table,pairs,next
4 minetest,vector,math,table,pairs,next
7 local get_node = minetest.get_node
8 local get_item_group = minetest.get_item_group
9 local get_meta = minetest.get_meta
10 local facedir_to_dir = minetest.facedir_to_dir
11 local content_id = minetest.get_name_from_content_id
12 local get_content_id = minetest.get_content_id
13 local get_voxel_manip = minetest.get_voxel_manip
14 local after = minetest.after
16 local swap_node = minetest.swap_node
17 local registered_nodes
18 minetest.register_on_mods_loaded(function()
19 registered_nodes = minetest.registered_nodes
24 local floor = math.floor
27 local new_vec = vector.new
28 local add_vec = vector.add
29 local sub_vec = vector.subtract
30 local vector_distance = vector.distance
31 local vec_equals = vector.equals
33 local activator_table = {} -- this holds the translation data of activator tables (activator functions)
34 local capacitor_table = {}
39 -- enables mods to create data functions
40 function redstone.register_activator(data)
41 activator_table[data.name] = {
42 activate = data.activate,
43 deactivate = data.deactivate
47 -- enables mods to create data functions
48 function redstone.register_capacitor(data)
49 capacitor_table[data.name] = {
55 local path = minetest.get_modpath("redstone")
56 dofile(path.."/functions.lua")
57 dofile(path.."/torch.lua")
58 dofile(path.."/lever.lua")
59 dofile(path.."/button.lua")
60 dofile(path.."/repeater.lua")
61 dofile(path.."/light.lua")
62 dofile(path.."/piston.lua")
63 --dofile(path.."/comparator.lua")
64 dofile(path.."/craft.lua")
65 --dofile(path.."/ore.lua")
66 dofile(path.."/inverter.lua")
67 --dofile(path.."/player_detector.lua")
68 dofile(path.."/space_maker.lua")
69 --dofile(path.."/pressure_plate.lua")
70 dofile(path.."/capacitors.lua")
73 --this is written out manually so that
74 --math.abs is not needed
76 {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
77 {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
79 {x=0, y=1, z=0}, {x= 0, y=-1, z=0},
81 {x=1, y=1, z=0}, {x=-1, y=1, z= 0},
82 {x=0, y=1, z=1}, {x= 0, y=1, z=-1},
84 {x=1, y=-1, z=0}, {x=-1, y=-1, z= 0},
85 {x=0, y=-1, z=1}, {x= 0, y=-1, z=-1},
88 --thanks to RhodiumToad for helping me figure out a good method to do this
90 local pool = {} -- this holds all redstone data (literal 3d virtual memory map)
93 local function data_injection(pos,data)
94 -- add data into 3d memory
96 if not pool[pos.x] then pool[pos.x] = {} end
97 if not pool[pos.x][pos.y] then pool[pos.x][pos.y] = {} end
98 pool[pos.x][pos.y][pos.z] = data
99 --delete data from 3d memory
101 if pool and pool[pos.x] and pool[pos.x][pos.y] then
102 pool[pos.x][pos.y][pos.z] = data
103 if pool[pos.x][pos.y] and not next(pool[pos.x][pos.y]) then
104 pool[pos.x][pos.y] = nil
105 -- only run this if y axis is empty
106 if pool[pos.x] and not next(pool[pos.x]) then
116 local function create_boundary_box(pos)
118 for x = pos.x-9,pos.x+9 do
120 for y = pos.y-9,pos.y+9 do
122 for z = pos.z-9,pos.z+9 do
123 temp_pool = pool[x][y][z]
125 if not table_3d[x] then table_3d[x] = {} end
126 if not table_3d[x][y] then table_3d[x][y] = {} end
128 if (x == pos.x-9 or x == pos.x+9 or
129 y == pos.y-9 or y == pos.y+9 or
130 z == pos.z-9 or z == pos.z+9) and
131 temp_pool.dust and temp_pool.dust > 1 then
132 table_3d[x][y][z] = {torch=temp_pool.dust}
134 if temp_pool.dust then
135 table_3d[x][y][z] = {dust=0,origin=temp_pool.dust}
137 table_3d[x][y][z] = temp_pool
151 local function capacitor_pathfind(source,mem_map)
152 for _,order in pairs(order) do
154 i = add_vec(source,order)
155 if not mem_map[i.x] then mem_map[i.x] = {} end
156 if not mem_map[i.x][i.y] then mem_map[i.x][i.y] = {} end
158 if not mem_map[i.x][i.y][i.z] then
160 if i and pool and pool[i.x] and pool[i.x][i.y] and pool[i.x][i.y][i.z] then
161 index = pool[i.x][i.y][i.z]
162 if index.capacitor then
163 mem_map[i.x][i.y][i.z] = {name = index.name, capacitor = 0, source = index.source}
167 capacitor_pathfind(i,mem_map)
178 local function capacitor_sniff(pos)
180 table_3d = capacitor_pathfind(pos,table_3d)
181 found = table_3d.found
184 for x,datax in pairs(table_3d) do
185 for y,datay in pairs(datax) do
186 for z,data in pairs(datay) do
187 temp_pool = pool[x][y][z]
189 temp_pool.capacitor = 1
190 if capacitor_table[temp_pool.name] then
191 swap_node(new_vec(x,y,z),{name=capacitor_table[temp_pool.name].on})
192 redstone.update(new_vec(x,y,z))
199 for x,datax in pairs(table_3d) do
200 for y,datay in pairs(datax) do
201 for z,data in pairs(datay) do
202 temp_pool = pool[x][y][z]
204 temp_pool.capacitor = 0
205 if capacitor_table[temp_pool.name] then
206 swap_node(new_vec(x,y,z),{name=capacitor_table[temp_pool.name].off})
207 redstone.update(new_vec(x,y,z))
222 local non_directional_activator = function(pos)
223 if pool[pos.x] and pool[pos.x][pos.y] and pool[pos.x][pos.y][pos.z] then
224 temp_pool = pool[pos.x][pos.y][pos.z]
225 for _,order in pairs(order) do
226 n_pos = add_vec(pos,order)
227 if pool[n_pos.x] and pool[n_pos.x][n_pos.y] and pool[n_pos.x][n_pos.y][n_pos.z] then
228 temp_pool2 = pool[n_pos.x][n_pos.y][n_pos.z]
230 if (not temp_pool2.directional_activator and temp_pool2.torch) or
231 (temp_pool2.dust and temp_pool2.dust > 0) or
232 (temp_pool2.torch_directional and vector.equals(temp_pool2.output, pos)) then
233 if activator_table[temp_pool.name].activate then
234 activator_table[temp_pool.name].activate(pos)
241 if activator_table[temp_pool.name].deactivate then
242 activator_table[temp_pool.name].deactivate(pos)
247 -- directional activators
253 local directional_activator = function(pos)
260 --if not (pool[pos.x] and pool[pos.x][pos.y] and pool[pos.x][pos.y][pos.z]) then return end
262 temp_pool = pool[pos.x][pos.y][pos.z]
264 if not temp_pool then ignore = true end
267 input = temp_pool.input
270 if not input then ignore = true end
273 input = temp_pool.input
276 if not ignore and pool and pool[input.x] and pool[input.x][input.y] and pool[input.x][input.y][input.z] then
277 temp_pool2 = pool[input.x][input.y][input.z]
282 if not temp_pool2 then ignore = true end
284 if not ignore and ((temp_pool2.dust and temp_pool2.dust > 0) or (temp_pool2.torch and temp_pool2.directional_activator and temp_pool2.dir == temp_pool.dir) or
285 (not temp_pool2.directional_activator and temp_pool2.torch) or (temp_pool2.capacitor and temp_pool2.capacitor > 0)) then
286 if activator_table[temp_pool.name].activate then
287 activator_table[temp_pool.name].activate(pos)
293 if activator_table[temp_pool.name].deactivate then
294 activator_table[temp_pool.name].deactivate(pos)
298 --make redstone wire pass on current one level lower than it is
301 local passed_on_level
302 local function redstone_pathfinder(source,source_level,mem_map,output)
303 if not source_level then return end
304 --directional torches
307 if i and mem_map and mem_map[i.x] and mem_map[i.x][i.y] and mem_map[i.x][i.y][i.z] then
308 index = mem_map[i.x][i.y][i.z]
311 passed_on_level = source_level - 1
312 if passed_on_level > 0 then
313 mem_map[i.x][i.y][i.z].dust = passed_on_level
314 redstone_pathfinder(i,passed_on_level,mem_map,nil)
320 for _,order in pairs(order) do
321 i = add_vec(source,order)
322 if i and mem_map and mem_map[i.x] and mem_map[i.x][i.y] and mem_map[i.x][i.y][i.z] then
323 index = mem_map[i.x][i.y][i.z]
325 passed_on_level = source_level - 1
326 if passed_on_level > 0 and index.dust < source_level then
327 mem_map[i.x][i.y][i.z].dust = passed_on_level
328 redstone_pathfinder(i,passed_on_level,mem_map,nil)
348 _,' _o\ ,::.`:' ; ; . '
352 `.______,-,----._ ,' ;: ,/ , ,`
353 / /,-';' \ ; `: ,'/,::.:::
354 ,',;-'-'_,--; ; :. ,',',;::::::
355 ( /___,-' `. ;::,,'o/ ,:::::::
364 local function dust_sniff(pos,mem_map,boundary)
365 for _,order in pairs(order) do
366 i = add_vec(pos,order)
368 if not mem_map[i.x] then mem_map[i.x] = {} end
369 if not mem_map[i.x][i.y] then mem_map[i.x][i.y] = {} end
371 if not mem_map[i.x][i.y][i.z] then
373 if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then
374 index = boundary[i.x][i.y][i.z]
377 mem_map[i.x][i.y][i.z] = index
378 mem_map[i.x][i.y][i.z].sniffed = true
380 dust_sniff(i,mem_map,boundary)
382 elseif index.directional_activator and vec_equals(pos,index.input) then
383 mem_map[i.x][i.y][i.z] = index
384 mem_map[i.x][i.y][i.z].sniffed = true
385 elseif index.torch and index.torch > 1 then
386 if index.torch_directional and vec_equals(pos,index.output) then
387 mem_map[i.x][i.y][i.z] = index
388 mem_map[i.x][i.y][i.z].sniffed = true
389 elseif not index.torch_directional then
390 mem_map[i.x][i.y][i.z] = index
391 mem_map[i.x][i.y][i.z].sniffed = true
393 elseif index.activator then
394 mem_map[i.x][i.y][i.z] = index
395 mem_map[i.x][i.y][i.z].sniffed = true
403 --make all power sources push power out
413 local function calculate(pos,is_capacitor)
414 if not is_capacitor then
415 boundary = create_boundary_box(pos)
418 dust_detected = false
421 --update needs to sniff it's own position
422 if boundary[pos.x] and boundary[pos.x][pos.y] and boundary[pos.x][pos.y][pos.z] then
423 if not dust_map[pos.x] then dust_map[pos.x] = {} end
424 if not dust_map[pos.x][pos.y] then dust_map[pos.x][pos.y] = {} end
425 dust_map[pos.x][pos.y][pos.z] = boundary[pos.x][pos.y][pos.z]
428 dust_sniff(pos,dust_map,boundary)
430 -- sniff all possible dust within boundaries
431 for _,pos2 in pairs(order) do
432 pos3 = add_vec(pos,pos2)
433 if boundary[pos3.x] and boundary[pos3.x][pos3.y] and boundary[pos3.x][pos3.y][pos3.z] and
434 not (dust_map[pos3.x] and dust_map[pos3.x][pos3.y] and dust_map[pos3.x][pos3.y][pos3.z] and dust_map[pos3.x][pos3.y][pos3.z].sniffed) then
435 temp_pool3 = boundary[pos3.x][pos3.y][pos3.z]
436 if temp_pool3.dust then
437 dust_sniff(pos3,dust_map,boundary)
443 for x,datax in pairs(dust_map) do
444 for y,datay in pairs(datax) do
445 for z,data in pairs(datay) do
448 if data.torch_directional then
449 redstone_pathfinder(new_vec(x,y,z),data.torch,dust_map,data.output)
451 redstone_pathfinder(new_vec(x,y,z),data.torch,dust_map)
452 dust_map[x][y][z] = nil
459 --set dust, set pool memory
460 for x,datax in pairs(dust_map) do
461 for y,datay in pairs(datax) do
462 for z,data in pairs(datay) do
463 if data.dust and data.dust ~= data.origin then
464 swap_node(new_vec(x,y,z),{name="redstone:dust_"..data.dust})
465 data_injection(new_vec(x,y,z),data)
466 --delete the data to speed up next loop
467 dust_map[x][y][z] = nil
474 --this must be run at the end
475 for x,datax in pairs(dust_map) do
476 for y,datay in pairs(datax) do
477 for z,data in pairs(datay) do
478 if data.directional_activator then
479 directional_activator(new_vec(x,y,z))
480 elseif data.activator then
481 non_directional_activator(new_vec(x,y,z))
492 function redstone.inject(pos,data)
493 data_injection(pos,data)
497 local recursion_check = {}
499 function redstone.update(pos,is_capacitor)
500 local s_pos = minetest.serialize(pos)
501 if not recursion_check[s_pos] then
502 recursion_check[s_pos] = 0
504 recursion_check[s_pos] = recursion_check[s_pos] + 1
505 if recursion_check[s_pos] > 25 then
506 --print(recursion_check[s_pos])
507 minetest.after(0,function()
508 bad_node = minetest.get_node(pos).name
509 bad_node = minetest.get_node_drops(bad_node, "main:rubypick")
510 for _,nodey in pairs(bad_node) do
511 minetest.throw_item(pos,nodey)
513 minetest.remove_node(pos)
514 data_injection(pos,nil)
520 calculate(pos,is_capacitor)
523 minetest.register_globalstep(function()
528 ----------------------------------------------------------------------------
562 minetest.register_craftitem("redstone:dust", {
563 description = "Redstone Dust",
564 inventory_image = "redstone_dust_item.png",
565 wield_image = "redstone_dust_item.png",
566 wield_scale = {x = 1, y = 1, z = 1 + 1/16},
567 liquids_pointable = false,
568 on_place = function(itemstack, placer, pointed_thing)
569 if not pointed_thing.type == "node" then
572 local sneak = placer:get_player_control().sneak
573 local noddef = registered_nodes[get_node(pointed_thing.under).name]
574 if not sneak and noddef.on_rightclick then
575 minetest.item_place(itemstack, placer, pointed_thing)
579 local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
581 itemstack:take_item()
587 --8 power levels 8 being the highest
590 local coloring = floor(color)
591 minetest.register_node("redstone:dust_"..i,{
592 description = "Redstone Dust",
593 wield_image = "redstone_dust_item.png",
595 "redstone_dust_main.png^[colorize:red:"..coloring, "redstone_turn.png^[colorize:red:"..coloring,
596 "redstone_t.png^[colorize:red:"..coloring, "redstone_cross.png^[colorize:red:"..coloring
599 drawtype = "raillike",
601 sunlight_propagates = true,
602 is_ground_content = false,
604 node_placement_prediction = "",
607 fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
609 sounds = main.stoneSound(),
610 groups={dig_immediate=1,attached_node=1,redstone_dust=1,redstone=1,redstone_power=i},
611 drop="redstone:dust",
612 on_construct = function(pos)
613 data_injection(pos,{dust=i})
616 after_destruct = function(pos)
617 data_injection(pos,nil)
620 connects_to = {"group:redstone"},
624 minetest.register_lbm({
625 name = "redstone:"..i,
626 nodenames = {"redstone:dust_"..i},
627 run_at_every_load = true,
628 action = function(pos)
629 data_injection(pos,{dust=i})