]> git.lizzy.rs Git - Crafter.git/blob - mods/redstone/init.lua
993561b5740c1d8c1cef56ca9d7c208f9905be73
[Crafter.git] / mods / redstone / init.lua
1 local 
2 minetest,vector,math,table,pairs,next
3 =
4 minetest,vector,math,table,pairs,next
5
6 -- minetest class
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
16 local swap_node       = minetest.swap_node
17 local registered_nodes
18 minetest.register_on_mods_loaded(function()
19         registered_nodes  = minetest.registered_nodes
20 end)
21
22 -- math class
23 local abs   = math.abs
24 local floor = math.floor
25
26 -- vector library
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
32 local activator_table = {} -- this holds the translation data of activator tables (activator functions)
33 local capacitor_table = {}
34
35 -- redstone class
36 redstone = {}
37
38 -- enables mods to create data functions
39 function redstone.register_activator(data)
40         activator_table[data.name] = {
41                 activate   = data.activate,
42                 deactivate = data.deactivate
43         }
44 end
45
46 -- enables mods to create data functions
47 function redstone.register_capacitor(data)
48         capacitor_table[data.name] = {
49                 off = data.off,
50                 on  = data.on
51         }
52 end
53
54 local path = minetest.get_modpath("redstone")
55 dofile(path.."/functions.lua")
56 --dofile(path.."/wire.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")
71
72
73 --this is written out manually so that
74 --math.abs is not needed
75 local order = {
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},
78
79         {x=0, y=1, z=0}, {x= 0, y=-1, z=0},
80
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},
83
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},
86 }
87
88 --thanks to RhodiumToad for helping me figure out a good method to do this
89
90 local pool = {} -- this holds all redstone data (literal 3d virtual memory map)
91
92
93 local function data_injection(pos,data)
94         -- add data into 3d memory
95         if data then
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
100         else
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
107                                         pool[pos.x] = nil
108                                 end
109                         end
110                 end
111         end
112 end
113
114 local table_3d
115 local temp_pool
116 local function create_boundary_box(pos)
117         table_3d = {}
118         for x = pos.x-9,pos.x+9 do
119                 if pool[x] then
120                         for y = pos.y-9,pos.y+9 do
121                                 if pool[x][y] then
122                                         for z = pos.z-9,pos.z+9 do
123                                                 temp_pool = pool[x][y][z]
124                                                 if temp_pool then
125                                                         if not table_3d[x] then table_3d[x] = {} end
126                                                         if not table_3d[x][y] then table_3d[x][y] = {} end
127
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}
133                                                         else
134                                                                 if temp_pool.dust then
135                                                                         table_3d[x][y][z] = {dust=0,origin=temp_pool.dust}
136                                                                 else
137                                                                         table_3d[x][y][z] = temp_pool
138                                                                 end
139                                                         end
140                                                 end
141                                         end
142                                 end
143                         end
144                 end
145         end
146         return(table_3d)
147 end
148
149
150 local function capacitor_pathfind(source,mem_map)
151         for _,order in pairs(order) do
152
153                 i = add_vec(source,order)
154                 if not mem_map[i.x] then mem_map[i.x] = {} end
155                 if not mem_map[i.x][i.y] then mem_map[i.x][i.y] = {} end
156
157                 if not mem_map[i.x][i.y][i.z] then
158
159                         if i and pool and pool[i.x] and pool[i.x][i.y] and pool[i.x][i.y][i.z] then
160                                 index = pool[i.x][i.y][i.z]
161                                 if index.capacitor then
162                                         mem_map[i.x][i.y][i.z] = {name = index.name, capacitor = 0, source = index.source}
163                                         if index.source then
164                                                 mem_map.found = true
165                                         end
166                                         capacitor_pathfind(i,mem_map)
167                                 end
168                         end
169                 end
170         end
171         return mem_map,found
172 end
173
174 local table_3d
175 local found
176 local temp_pool
177 local function capacitor_sniff(pos)
178         table_3d = {}
179         table_3d = capacitor_pathfind(pos,table_3d)
180         found = table_3d.found
181         table_3d.found = nil
182         if found then
183                 for x,datax in pairs(table_3d) do
184                         for y,datay in pairs(datax) do
185                                 for z,data in pairs(datay) do
186                                         temp_pool = pool[x][y][z]
187                                         if temp_pool then
188                                                 temp_pool.capacitor = 1
189                                                 if capacitor_table[temp_pool.name] then
190                                                         swap_node(new_vec(x,y,z),{name=capacitor_table[temp_pool.name].on})
191                                                         redstone.update(new_vec(x,y,z))
192                                                 end
193                                         end
194                                 end
195                         end
196                 end
197         else
198                 for x,datax in pairs(table_3d) do
199                         for y,datay in pairs(datax) do
200                                 for z,data in pairs(datay) do
201                                         temp_pool = pool[x][y][z]
202                                         if temp_pool then
203                                                 temp_pool.capacitor = 0
204                                                 if capacitor_table[temp_pool.name] then
205                                                         swap_node(new_vec(x,y,z),{name=capacitor_table[temp_pool.name].off})
206                                                         redstone.update(new_vec(x,y,z))
207                                                 end
208                                         end
209                                 end
210                         end
211                 end
212         end
213 end
214
215
216
217 -- activators
218 local n_pos
219 local temp_pool
220 local temp_pool2
221 local non_directional_activator = function(pos)
222         if pool[pos.x] and pool[pos.x][pos.y] and pool[pos.x][pos.y][pos.z] then
223                 temp_pool = pool[pos.x][pos.y][pos.z]
224                 for _,order in pairs(order) do
225                         n_pos = add_vec(pos,order)
226                         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
227                                 temp_pool2 = pool[n_pos.x][n_pos.y][n_pos.z]
228                                 if temp_pool2 then
229                                         if (not temp_pool2.directional_activator and temp_pool2.torch) or 
230                                         (temp_pool2.dust and temp_pool2.dust > 0) or 
231                                         (temp_pool2.torch_directional and vector.equals(temp_pool2.output, pos)) then
232                                                 if activator_table[temp_pool.name].activate then
233                                                         activator_table[temp_pool.name].activate(pos)
234                                                 end
235                                                 return
236                                         end
237                                 end
238                         end
239                 end     
240                 if activator_table[temp_pool.name].deactivate then
241                         activator_table[temp_pool.name].deactivate(pos)
242                 end
243         end
244 end
245
246 -- directional activators
247 local n_pos
248 local temp_pool
249 local temp_pool2
250 local input
251 local ignore
252 local directional_activator = function(pos)
253         
254         ignore = false
255         input = nil
256         temp_pool2 = nil
257
258         temp_pool = pool[pos.x][pos.y][pos.z]
259         
260         if not temp_pool then ignore = true end
261
262         if not ignore then
263                 input = temp_pool.input
264         end
265
266         if not input then ignore = true end
267
268         if not ignore then
269                 input = temp_pool.input
270         end
271
272         if not ignore and pool and pool[input.x] and pool[input.x][input.y] and pool[input.x][input.y][input.z] then
273                 temp_pool2 = pool[input.x][input.y][input.z]
274         else
275                 ignore = true
276         end
277
278         if not temp_pool2 then ignore = true end
279
280         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 
281         (not temp_pool2.directional_activator and temp_pool2.torch) or (temp_pool2.capacitor and temp_pool2.capacitor > 0))  then
282                 if activator_table[temp_pool.name].activate then
283                         activator_table[temp_pool.name].activate(pos)
284                         return
285                 end
286                 return
287         end
288
289         if activator_table[temp_pool.name].deactivate then
290                 activator_table[temp_pool.name].deactivate(pos)
291         end
292 end
293
294 --make redstone wire pass on current one level lower than it is
295 local i
296 local index
297 local passed_on_level
298 local function redstone_pathfinder(source,source_level,boundary,output)
299         if not source_level then return end
300         --directional torches
301         if output then
302                 i = output
303                 if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then
304                         index = boundary[i.x][i.y][i.z]
305                         --dust
306                         if index.dust then
307                                 passed_on_level = source_level - 1
308                                 if passed_on_level > 0 then
309                                         boundary[i.x][i.y][i.z].dust = passed_on_level
310                                         redstone_pathfinder(i,passed_on_level,boundary,nil)
311                                 end
312                         end
313                 end
314         else
315                 --redstone and torch
316                 for _,order in pairs(order) do
317                         i = add_vec(source,order)
318                         if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then
319                                 index = boundary[i.x][i.y][i.z]
320                                 if index.dust then
321                                         passed_on_level = source_level - 1
322                                         if passed_on_level > 0 and index.dust < source_level then
323                                                 boundary[i.x][i.y][i.z].dust = passed_on_level
324                                                 redstone_pathfinder(i,passed_on_level,boundary,nil)
325                                         end
326                                 end
327                         end
328                 end
329         end
330         return(boundary)
331 end
332
333
334
335
336 --make all power sources push power out
337 local pos
338 local node
339 local power
340 local boundary
341 local function calculate(pos,is_capacitor)
342         if not is_capacitor then
343                 boundary = create_boundary_box(pos)
344                 --pathfind through memory map   
345                 for x,index_x in pairs(boundary) do
346                         for y,index_y in pairs(index_x) do
347                                 for z,data in pairs(index_y) do
348                                         --allow data values for torches
349                                         if data.torch and not data.torch_directional then
350                                                 redstone_pathfinder(new_vec(x,y,z),data.torch,boundary)
351                                                 boundary[x][y][z] = nil
352                                         elseif data.torch_directional then
353                                                 redstone_pathfinder(new_vec(x,y,z),data.torch,boundary,data.output)
354                                         end
355                                 end
356                         end
357                 end
358                 --reassemble the table into a position list minetest can understand
359                 --run through and set dust
360                 for x,datax in pairs(boundary) do
361                         for y,datay in pairs(datax) do
362                                 for z,data in pairs(datay) do
363                                         if data.dust and data.dust ~= data.origin then
364                                                 swap_node(new_vec(x,y,z),{name="redstone:dust_"..data.dust})
365                                         end
366                                         --write data back to memory pool
367                                         pool[x][y][z] = data
368
369                                         if data.dust then
370                                                 --delete the data to speed up next loop
371                                                 boundary[x][y][z] = nil
372                                         end
373                                 end
374                         end
375                 end
376
377                 
378                 --this must be done after the memory is written
379                 for x,datax in pairs(boundary) do
380                         for y,datay in pairs(datax) do
381                                 for z,data in pairs(datay) do
382                                         if data.directional_activator then
383                                                 directional_activator(new_vec(x,y,z))
384                                         elseif data.activator then
385                                                 non_directional_activator(new_vec(x,y,z))
386                                         end
387                                 end
388                         end
389                 end
390         else
391                 capacitor_sniff(pos)
392         end
393 end
394
395
396 function redstone.inject(pos,data)
397         data_injection(pos,data)
398 end
399
400
401 local recursion_check = {}
402 local bad_node
403 function redstone.update(pos,is_capacitor)
404         local s_pos = minetest.serialize(pos)
405         if not recursion_check[s_pos] then
406                 recursion_check[s_pos] = 0
407         end
408         recursion_check[s_pos] = recursion_check[s_pos] + 1
409         if recursion_check[s_pos] > 25 then
410                 --print(recursion_check[s_pos])
411                 minetest.after(0,function()
412                         bad_node = minetest.get_node(pos).name
413                         bad_node = minetest.get_node_drops(bad_node, "main:rubypick")
414                         for _,nodey in pairs(bad_node) do
415                                 minetest.throw_item(pos,nodey)
416                         end
417                         minetest.dig_node(pos)
418                         data_injection(pos,nil)
419                         redstone.update(pos)
420                 end)
421                 return
422         end
423
424         calculate(pos,is_capacitor)
425 end
426
427 minetest.register_globalstep(function()
428         recursion_check = {}
429 end)
430
431
432 ----------------------------------------------------------------------------
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466 minetest.register_craftitem("redstone:dust", {
467         description = "Redstone Dust",
468         inventory_image = "redstone_dust_item.png",
469         wield_image = "redstone_dust_item.png",
470         wield_scale = {x = 1, y = 1, z = 1 + 1/16},
471         liquids_pointable = false,
472         on_place = function(itemstack, placer, pointed_thing)
473                 if not pointed_thing.type == "node" then
474                         return
475                 end             
476                 local sneak = placer:get_player_control().sneak
477                 local noddef = registered_nodes[get_node(pointed_thing.under).name]
478                 if not sneak and noddef.on_rightclick then
479                         minetest.item_place(itemstack, placer, pointed_thing)
480                         return
481                 end
482                 
483                 local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
484                 if worked then
485                         itemstack:take_item()
486                         return(itemstack)
487                 end
488
489
490                         --minetest.add_node(pointed_thing.above, {name="redstone:dust_0"})
491                         --itemstack:take_item(1)
492                         --minetest.sound_play("stone", {pos=pointed_thing.above})
493                         --return(itemstack)
494                 --end
495         end,
496 })
497
498 --8 power levels 8 being the highest
499 local color = 0
500 for i = 0,8 do
501         local coloring = floor(color)
502         minetest.register_node("redstone:dust_"..i,{
503                 description = "Redstone Dust",
504                 wield_image = "redstone_dust_item.png",
505                 tiles = {
506                         "redstone_dust_main.png^[colorize:red:"..coloring, "redstone_turn.png^[colorize:red:"..coloring,
507                         "redstone_t.png^[colorize:red:"..coloring, "redstone_cross.png^[colorize:red:"..coloring
508                 },
509                 power=i,
510                 drawtype = "raillike",
511                 paramtype = "light",
512                 sunlight_propagates = true,
513                 is_ground_content = false,
514                 walkable = false,
515                 node_placement_prediction = "",
516                 selection_box = {
517                         type = "fixed",
518                         fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
519                 },
520                 sounds = main.stoneSound(),
521                 groups={dig_immediate=1,attached_node=1,redstone_dust=1,redstone=1,redstone_power=i},
522                 drop="redstone:dust",
523                 on_construct = function(pos)
524                         data_injection(pos,{dust=i})
525                         calculate(pos)
526                 end,
527                 after_destruct = function(pos)
528                         data_injection(pos,nil)
529                         calculate(pos)
530                 end,
531                 connects_to = {"group:redstone"},
532         })
533         color= color +31.875
534
535         minetest.register_lbm({
536         name = "redstone:"..i,
537                 nodenames = {"redstone:dust_"..i},
538                 run_at_every_load = true,
539         action = function(pos)
540             data_injection(pos,{dust=i})
541         end,
542     })
543 end