2 minetest,vector,math,table,pairs
4 minetest,vector,math,table,pairs
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
15 local set_node = minetest.set_node
16 local registered_nodes
17 minetest.register_on_mods_loaded(function()
18 registered_nodes = minetest.registered_nodes
23 local floor = math.floor
26 local new_vec = vector.new
27 local add_vec = vector.add
28 local sub_vec = vector.subtract
29 local vector_distance = vector.distance
31 --this is written out manually so that
32 --math.abs is not needed
34 {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
35 {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
37 {x=0, y=1, z=0}, {x= 0, y=-1, z=0},
39 {x=1, y=1, z=0}, {x=-1, y=1, z= 0},
40 {x=0, y=1, z=1}, {x= 0, y=1, z=-1},
42 {x=1, y=-1, z=0}, {x=-1, y=-1, z= 0},
43 {x=0, y=-1, z=1}, {x= 0, y=-1, z=-1},
53 local check_table = {}
55 local path = minetest.get_modpath("redstone")
56 dofile(path.."/functions.lua")
57 dofile(path.."/wire.lua")
58 dofile(path.."/torch.lua")
59 dofile(path.."/lever.lua")
60 dofile(path.."/button.lua")
61 dofile(path.."/repeater.lua")
62 dofile(path.."/light.lua")
63 dofile(path.."/piston.lua")
64 dofile(path.."/comparator.lua")
65 dofile(path.."/craft.lua")
66 dofile(path.."/ore.lua")
67 dofile(path.."/inverter.lua")
68 dofile(path.."/player_detector.lua")
69 dofile(path.."/space_maker.lua")
70 dofile(path.."/pressure_plate.lua")
73 --set the data for powered states
74 local get_local_power = function(pos)
78 for _,order in pairs(order) do
79 --print(get_node(add_vec(new_vec(x,y,z),pos)).name)
80 if get_item_group(get_node(add_vec(new_vec(order.x,order.y,order.z),pos)).name, "redstone_power") > 0 then
83 if get_meta(add_vec(new_vec(order.x,order.y,order.z),pos)):get_int("redstone_power") > 0 then
92 local get_powered_state_directional = function(pos)
93 pos = sub_vec(pos,facedir_to_dir(get_node(pos).param2))
94 power = get_item_group(get_node(pos).name, "redstone_power")
96 power = get_meta(pos):get_int("redstone_power")
102 local redstone_activate = function(pos,power)
104 node = get_node(pos).name
105 if registered_nodes[node].redstone_activation then
106 registered_nodes[node].redstone_activation(pos)
112 local redstone_deactivate = function(pos,power)
114 node = get_node(pos).name
115 if registered_nodes[node].redstone_deactivation then
116 registered_nodes[node].redstone_deactivation(pos)
121 --collect all nodes that are local to the modified
122 --node of redstone dust and store in memory
123 local localredstone = {}
125 localredstone.injector = function(i,origin)
126 node = get_node(i).name
127 if node == "air" then
131 if r_index[i.x] and r_index[i.x][i.y] and r_index[i.x][i.y][i.z] then
135 if vector_distance(i,origin) > 9 then
140 if get_item_group(node,"redstone_dust") > 0 then
141 if vector_distance(i,origin) <= 8 then
142 --add data to both maps
143 if not r_index[i.x] then r_index[i.x] = {} end
144 if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
145 r_index[i.x][i.y][i.z] = {dust = true,level = 0}
147 if not check_table[i.x] then check_table[i.x] = {} end
148 if not check_table[i.x][i.y] then check_table[i.x][i.y] = {} end
149 check_table[i.x][i.y][i.z] = get_item_group(node,"redstone_power")
151 --the data to the 3d array must be written to memory before this is executed
152 --or a stack overflow occurs!!!
153 localredstone.collector(i,origin)
156 if not r_index[i.x] then r_index[i.x] = {} end
157 if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
158 r_index[i.x][i.y][i.z] = {torch = true,power=get_item_group(node,"redstone_power")}
161 --index power sources
162 if get_item_group(node,"redstone_torch") > 0 then
163 if not r_index[i.x] then r_index[i.x] = {} end
164 if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
165 r_index[i.x][i.y][i.z] = {torch = true,power=get_item_group(node,"redstone_power")}
167 --index directional power sources (Like repeaters/comparators)
168 --only outputs forwards
169 if get_item_group(node,"torch_directional") > 0 then
170 if not r_index[i.x] then r_index[i.x] = {} end
171 if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
172 r_index[i.x][i.y][i.z] = {torch_directional = true, dir = get_node(i).param2 , power = get_item_group(node,"redstone_power")}
175 --index directional activators (Like repeaters/comparators)
176 --only accepts input from the back
177 if get_item_group(node,"redstone_activation_directional") > 0 then
178 --print("indexing directional")
179 if not a_index[i.x] then a_index[i.x] = {} end
180 if not a_index[i.x][i.y] then a_index[i.x][i.y] = {} end
181 if not a_index[i.x][i.y][i.z] then a_index[i.x][i.y][i.z] = {} end
183 a_index[i.x][i.y][i.z].redstone_activation = true
184 a_index[i.x][i.y][i.z].directional = true
187 --index objects that activate
188 if get_item_group(node,"redstone_activation") > 0 then
189 if not a_index[i.x] then a_index[i.x] = {} end
190 if not a_index[i.x][i.y] then a_index[i.x][i.y] = {} end
191 if not a_index[i.x][i.y][i.z] then a_index[i.x][i.y][i.z] = {} end
192 a_index[i.x][i.y][i.z].redstone_activation = true
195 --sneaky way to make levers and buttons work
196 if get_meta(i):get_int("redstone_power") > 0 then
197 if not r_index[i.x] then r_index[i.x] = {} end
198 if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
199 r_index[i.x][i.y][i.z] = {torch = true,power=get_meta(i):get_int("redstone_power")}
203 localredstone.collector = function(pos,origin)
204 for _,order in pairs(order) do
205 localredstone.injector(add_vec(pos,new_vec(order.x,order.y,order.z)),origin)
210 --check if index table contains items
211 --then execute an update
212 local function redstone_algorithm()
213 --if indexes exist then calculate redstone
214 --create the old version to help with deactivation calculation
216 --clear the index to avoid cpu looping wasting processing power
223 function redstone.collect_info(pos)
224 if r_index[pos.x] and r_index[pos.x][pos.y] and r_index[pos.x][pos.y][pos.z] then
227 localredstone.injector(pos,pos)
228 localredstone.collector(pos,pos)
234 --make all power sources push power out
238 function redstone.calculate()
239 --speed_test = minetest.get_us_time()/1000000
241 --pathfind through memory map
242 for x,index_x in pairs(r_index) do
243 for y,index_y in pairs(index_x) do
244 for z,data in pairs(index_y) do
245 --allow data values for torches
247 redstone.pathfind(new_vec(x,y,z),data.power)
248 r_index[x][y][z] = nil
249 elseif data.torch_directional then
250 redstone.pathfind(new_vec(x,y,z),data.power,data.dir)
251 r_index[x][y][z] = nil
257 --print("total torch calc time:"..minetest.get_us_time()/1000000-speed_test)
261 --reassemble the table into a position list minetest can understand
262 --run through and set dust
265 for x,datax in pairs(r_index) do
266 for y,datay in pairs(datax) do
267 for z,index in pairs(datay) do
268 --print(get_node(new_vec(x,y,z)).name)
269 if index and index.dust and index.level ~= check_table[x][y][z] then
271 set_node(new_vec(x,y,z),{name="redstone:dust_"..index.level})
276 --print("set "..count.." nodes")
278 for x,datax in pairs(a_index) do
279 for y,datay in pairs(datax) do
280 for z,index in pairs(datay) do
281 --directional activators
282 if index.directional == true then
283 power = get_powered_state_directional(new_vec(x,y,z))
286 redstone_activate(new_vec(x,y,z),power)
287 elseif power == 0 then
288 redstone_deactivate(new_vec(x,y,z),power)
291 --non directional activators
293 power = get_local_power(new_vec(x,y,z))
297 redstone_activate(new_vec(x,y,z),power)
298 elseif power == 0 then
299 redstone_deactivate(new_vec(x,y,z),power)
308 --make redstone wire pass on current one level lower than it is
311 local passed_on_level
312 local function redstone_pathfinder(source,source_level,direction)
313 --directional torches
316 --print("starting direction")
317 i = add_vec(source,facedir_to_dir(direction))
318 if r_index and r_index[i.x] and r_index[i.x][i.y] and r_index[i.x][i.y][i.z] then
319 index = r_index[i.x][i.y][i.z]
322 passed_on_level = source_level - 1
323 if passed_on_level > 0 then
324 r_index[i.x][i.y][i.z].level = passed_on_level
325 redstone_pathfinder(i,passed_on_level,nil)
331 for _,order in pairs(order) do
332 i = add_vec(source,new_vec(order.x,order.y,order.z))
333 if r_index and r_index[i.x] and r_index[i.x][i.y] and r_index[i.x][i.y][i.z] then
334 --print(minetest.get_node(i).name)
335 index = r_index[i.x][i.y][i.z]
337 passed_on_level = source_level - 1
338 if passed_on_level > 0 and index.level < source_level then
339 r_index[i.x][i.y][i.z].level = passed_on_level
340 redstone_pathfinder(i,passed_on_level,nil)
347 function redstone.pathfind(source,source_level,direction)
348 redstone_pathfinder(source,source_level,direction)
358 ----------------------------------------------------------------------------
392 minetest.register_craftitem("redstone:dust", {
393 description = "Redstone Dust",
394 inventory_image = "redstone_dust_item.png",
395 wield_image = "redstone_dust_item.png",
396 wield_scale = {x = 1, y = 1, z = 1 + 1/16},
397 liquids_pointable = false,
398 on_place = function(itemstack, placer, pointed_thing)
399 if not pointed_thing.type == "node" then
402 local sneak = placer:get_player_control().sneak
403 local noddef = registered_nodes[get_node(pointed_thing.under).name]
404 if not sneak and noddef.on_rightclick then
405 minetest.item_place(itemstack, placer, pointed_thing)
409 local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
411 itemstack:take_item()
416 --minetest.add_node(pointed_thing.above, {name="redstone:dust_0"})
417 --itemstack:take_item(1)
418 --minetest.sound_play("stone", {pos=pointed_thing.above})
424 --8 power levels 8 being the highest
427 local coloring = floor(color)
428 minetest.register_node("redstone:dust_"..i,{
429 description = "Redstone Dust",
430 wield_image = "redstone_dust_item.png",
432 "redstone_dust_main.png^[colorize:red:"..coloring, "redstone_turn.png^[colorize:red:"..coloring,
433 "redstone_t.png^[colorize:red:"..coloring, "redstone_cross.png^[colorize:red:"..coloring
436 drawtype = "raillike",
438 sunlight_propagates = true,
439 is_ground_content = false,
441 node_placement_prediction = "",
444 fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
446 sounds = main.stoneSound(),
447 groups={dig_immediate=1,attached_node=1,redstone_dust=1,redstone=1,redstone_power=i},
448 drop="redstone:dust",
449 on_construct = function(pos)
450 redstone.collect_info(pos)
452 after_destruct = function(pos)
453 --redstone.remove(pos,registered_nodes[get_node(pos).name].power)
454 redstone.collect_info(pos)
456 connects_to = {"group:redstone"},