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
32 local activator_table = {} -- this holds the translation data of activator tables (activator functions)
37 -- enables mods to create data functions
38 function redstone.register_activator(data)
39 activator_table[data.name] = {
40 activate = data.activate,
41 deactivate = data.deactivate
45 local path = minetest.get_modpath("redstone")
46 dofile(path.."/functions.lua")
47 --dofile(path.."/wire.lua")
48 dofile(path.."/torch.lua")
49 dofile(path.."/lever.lua")
50 dofile(path.."/button.lua")
51 dofile(path.."/repeater.lua")
52 dofile(path.."/light.lua")
53 dofile(path.."/piston.lua")
54 --dofile(path.."/comparator.lua")
55 --dofile(path.."/craft.lua")
56 --dofile(path.."/ore.lua")
57 dofile(path.."/inverter.lua")
58 --dofile(path.."/player_detector.lua")
59 --dofile(path.."/space_maker.lua")
60 --dofile(path.."/pressure_plate.lua")
63 --this is written out manually so that
64 --math.abs is not needed
66 {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
67 {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
69 {x=0, y=1, z=0}, {x= 0, y=-1, z=0},
71 {x=1, y=1, z=0}, {x=-1, y=1, z= 0},
72 {x=0, y=1, z=1}, {x= 0, y=1, z=-1},
74 {x=1, y=-1, z=0}, {x=-1, y=-1, z= 0},
75 {x=0, y=-1, z=1}, {x= 0, y=-1, z=-1},
78 --thanks to RhodiumToad for helping me figure out a good method to do this
80 local pool = {} -- this holds all redstone data (literal 3d virtual memory map)
84 local function create_boundary_box(pos)
86 for x = pos.x-9,pos.x+9 do
88 for y = pos.y-9,pos.y+9 do
90 for z = pos.z-9,pos.z+9 do
91 temp_pool = pool[x][y][z]
93 if not table_3d[x] then table_3d[x] = {} end
94 if not table_3d[x][y] then table_3d[x][y] = {} end
96 if (x == pos.x-9 or x == pos.x+9 or
97 y == pos.y-9 or y == pos.y+9 or
98 z == pos.z-9 or z == pos.z+9) and
99 temp_pool.dust and temp_pool.dust > 1 then
100 table_3d[x][y][z] = {torch=temp_pool.dust}
102 if temp_pool.dust then
103 table_3d[x][y][z] = {dust=0,origin=temp_pool.dust}
105 table_3d[x][y][z] = temp_pool
117 local function data_injection(pos,data)
118 -- add data into 3d memory
120 if not pool[pos.x] then pool[pos.x] = {} end
121 if not pool[pos.x][pos.y] then pool[pos.x][pos.y] = {} end
122 pool[pos.x][pos.y][pos.z] = data
123 --delete data from 3d memory
125 if pool and pool[pos.x] and pool[pos.x][pos.y] then
126 pool[pos.x][pos.y][pos.z] = data
127 if pool[pos.x][pos.y] and not next(pool[pos.x][pos.y]) then
128 pool[pos.x][pos.y] = nil
129 -- only run this if y axis is empty
130 if pool[pos.x] and not next(pool[pos.x]) then
143 local non_directional_activator = function(pos)
144 if pool[pos.x] and pool[pos.x][pos.y] and pool[pos.x][pos.y][pos.z] then
145 temp_pool = pool[pos.x][pos.y][pos.z]
146 for _,order in pairs(order) do
147 n_pos = add_vec(pos,order)
148 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
149 temp_pool2 = pool[n_pos.x][n_pos.y][n_pos.z]
151 if (not temp_pool2.directional_activator and temp_pool2.torch) or
152 (temp_pool2.dust and temp_pool2.dust > 0) or
153 (temp_pool2.torch_directional and vector.equals(temp_pool2.output, pos)) then
154 if activator_table[temp_pool.name].activate then
155 activator_table[temp_pool.name].activate(pos)
162 if activator_table[temp_pool.name].deactivate then
163 activator_table[temp_pool.name].deactivate(pos)
168 -- directional activators
174 local directional_activator = function(pos)
180 temp_pool = pool[pos.x][pos.y][pos.z]
182 if not temp_pool then ignore = true end
185 input = temp_pool.input
188 if not input then ignore = true end
191 input = temp_pool.input
194 if not ignore and pool and pool[input.x] and pool[input.x][input.y] and pool[input.x][input.y][input.z] then
195 temp_pool2 = pool[input.x][input.y][input.z]
200 if not temp_pool2 then ignore = true end
202 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
203 (not temp_pool2.directional_activator and temp_pool2.torch)) then
204 if activator_table[temp_pool.name].activate then
205 activator_table[temp_pool.name].activate(pos)
211 if activator_table[temp_pool.name].deactivate then
212 activator_table[temp_pool.name].deactivate(pos)
216 --make redstone wire pass on current one level lower than it is
219 local passed_on_level
220 local function redstone_pathfinder(source,source_level,boundary,output)
221 if not source_level then return end
222 --directional torches
225 if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then
226 index = boundary[i.x][i.y][i.z]
229 passed_on_level = source_level - 1
230 if passed_on_level > 0 then
231 boundary[i.x][i.y][i.z].dust = passed_on_level
232 redstone_pathfinder(i,passed_on_level,boundary,nil)
238 for _,order in pairs(order) do
239 i = add_vec(source,new_vec(order.x,order.y,order.z))
240 if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then
241 index = boundary[i.x][i.y][i.z]
243 passed_on_level = source_level - 1
244 if passed_on_level > 0 and index.dust < source_level then
245 boundary[i.x][i.y][i.z].dust = passed_on_level
246 redstone_pathfinder(i,passed_on_level,boundary,nil)
258 --make all power sources push power out
263 local function calculate(pos)
264 boundary = create_boundary_box(pos)
265 --pathfind through memory map
266 for x,index_x in pairs(boundary) do
267 for y,index_y in pairs(index_x) do
268 for z,data in pairs(index_y) do
269 --allow data values for torches
270 if data.torch and not data.torch_directional then
271 redstone_pathfinder(new_vec(x,y,z),data.torch,boundary)
272 boundary[x][y][z] = nil
273 elseif data.torch_directional then
274 redstone_pathfinder(new_vec(x,y,z),data.torch,boundary,data.output)
279 --reassemble the table into a position list minetest can understand
280 --run through and set dust
281 for x,datax in pairs(boundary) do
282 for y,datay in pairs(datax) do
283 for z,data in pairs(datay) do
284 if data.dust and data.dust ~= data.origin then
285 swap_node(new_vec(x,y,z),{name="redstone:dust_"..data.dust})
288 --write data back to memory pool
292 --delete the data to speed up next loop
293 boundary[x][y][z] = nil
300 --this must be done after the memory is written
301 for x,datax in pairs(boundary) do
302 for y,datay in pairs(datax) do
303 for z,data in pairs(datay) do
304 if data.directional_activator then
305 directional_activator(new_vec(x,y,z))
306 elseif data.activator then
307 non_directional_activator(new_vec(x,y,z))
315 function redstone.inject(pos,data)
316 data_injection(pos,data)
320 local recursion_check = {}
321 function redstone.update(pos)
322 local s_pos = minetest.serialize(pos)
323 if not recursion_check[s_pos] then
324 recursion_check[s_pos] = 0
326 recursion_check[s_pos] = recursion_check[s_pos] + 1
327 --print(recursion_check[s_pos])
328 if recursion_check[s_pos] > 6 then
329 minetest.after(0,function()
330 minetest.dig_node(pos)
331 data_injection(pos,nil)
340 minetest.register_globalstep(function()
345 ----------------------------------------------------------------------------
379 minetest.register_craftitem("redstone:dust", {
380 description = "Redstone Dust",
381 inventory_image = "redstone_dust_item.png",
382 wield_image = "redstone_dust_item.png",
383 wield_scale = {x = 1, y = 1, z = 1 + 1/16},
384 liquids_pointable = false,
385 on_place = function(itemstack, placer, pointed_thing)
386 if not pointed_thing.type == "node" then
389 local sneak = placer:get_player_control().sneak
390 local noddef = registered_nodes[get_node(pointed_thing.under).name]
391 if not sneak and noddef.on_rightclick then
392 minetest.item_place(itemstack, placer, pointed_thing)
396 local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
398 itemstack:take_item()
403 --minetest.add_node(pointed_thing.above, {name="redstone:dust_0"})
404 --itemstack:take_item(1)
405 --minetest.sound_play("stone", {pos=pointed_thing.above})
411 --8 power levels 8 being the highest
414 local coloring = floor(color)
415 minetest.register_node("redstone:dust_"..i,{
416 description = "Redstone Dust",
417 wield_image = "redstone_dust_item.png",
419 "redstone_dust_main.png^[colorize:red:"..coloring, "redstone_turn.png^[colorize:red:"..coloring,
420 "redstone_t.png^[colorize:red:"..coloring, "redstone_cross.png^[colorize:red:"..coloring
423 drawtype = "raillike",
425 sunlight_propagates = true,
426 is_ground_content = false,
428 node_placement_prediction = "",
431 fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
433 sounds = main.stoneSound(),
434 groups={dig_immediate=1,attached_node=1,redstone_dust=1,redstone=1,redstone_power=i},
435 drop="redstone:dust",
436 on_construct = function(pos)
437 data_injection(pos,{dust=i})
440 after_destruct = function(pos)
441 data_injection(pos,nil)
444 connects_to = {"group:redstone"},
448 minetest.register_lbm({
449 name = "redstone:"..i,
450 nodenames = {"redstone:dust_"..i},
451 run_at_every_load = true,
452 action = function(pos)
453 data_injection(pos,{dust=i})