]> git.lizzy.rs Git - Crafter.git/blob - mods/redstone/init.lua
ee886ba3c99867975ac66aa2533a5cb6b790e104
[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
34 -- redstone class
35 redstone = {}
36
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
42         }
43 end
44
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")
61
62
63 --this is written out manually so that
64 --math.abs is not needed
65 local order = {
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},
68
69         {x=0, y=1, z=0}, {x= 0, y=-1, z=0},
70
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},
73
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},
76 }
77
78 --thanks to RhodiumToad for helping me figure out a good method to do this
79
80 local pool = {} -- this holds all redstone data (literal 3d virtual memory map)
81
82 local table_3d
83 local temp_pool
84 local function create_boundary_box(pos)
85         table_3d = {}
86         for x = pos.x-9,pos.x+9 do
87                 if pool[x] then
88                         for y = pos.y-9,pos.y+9 do
89                                 if pool[x][y] then
90                                         for z = pos.z-9,pos.z+9 do
91                                                 temp_pool = pool[x][y][z]
92                                                 if temp_pool then
93                                                         if not table_3d[x] then table_3d[x] = {} end
94                                                         if not table_3d[x][y] then table_3d[x][y] = {} end
95
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}
101                                                         else
102                                                                 if temp_pool.dust then
103                                                                         table_3d[x][y][z] = {dust=0,origin=temp_pool.dust}
104                                                                 else
105                                                                         table_3d[x][y][z] = temp_pool
106                                                                 end
107                                                         end
108                                                 end
109                                         end
110                                 end
111                         end
112                 end
113         end
114         return(table_3d)
115 end
116
117 local function data_injection(pos,data)
118         -- add data into 3d memory
119         if data then
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
124         else
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
131                                         pool[pos.x] = nil
132                                 end
133                         end
134                 end
135         end
136 end
137
138
139 -- activators
140 local n_pos
141 local temp_pool
142 local temp_pool2
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]
150                                 if temp_pool2 then
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)
156                                                 end
157                                                 return
158                                         end
159                                 end
160                         end
161                 end     
162                 if activator_table[temp_pool.name].deactivate then
163                         activator_table[temp_pool.name].deactivate(pos)
164                 end
165         end
166 end
167
168 -- directional activators
169 local n_pos
170 local temp_pool
171 local temp_pool2
172 local input
173 local ignore
174 local directional_activator = function(pos)
175         
176         ignore = false
177         input = nil
178         temp_pool2 = nil
179
180         temp_pool = pool[pos.x][pos.y][pos.z]
181         
182         if not temp_pool then ignore = true end
183
184         if not ignore then
185                 input = temp_pool.input
186         end
187
188         if not input then ignore = true end
189
190         if not ignore then
191                 input = temp_pool.input
192         end
193
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]
196         else
197                 ignore = true
198         end
199
200         if not temp_pool2 then ignore = true end
201
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)
206                         return
207                 end
208                 return
209         end
210
211         if activator_table[temp_pool.name].deactivate then
212                 activator_table[temp_pool.name].deactivate(pos)
213         end
214 end
215
216 --make redstone wire pass on current one level lower than it is
217 local i
218 local index
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
223         if output then
224                 i = output
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]
227                         --dust
228                         if index.dust then
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)
233                                 end
234                         end
235                 end
236         else
237                 --redstone and torch
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]
242                                 if index.dust then
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)
247                                         end
248                                 end
249                         end
250                 end
251         end
252         return(boundary)
253 end
254
255
256
257
258 --make all power sources push power out
259 local pos
260 local node
261 local power
262 local boundary
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)
275                                 end
276                         end
277                 end
278         end
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})
286                                 end
287
288                                 --write data back to memory pool
289                                 pool[x][y][z] = data
290
291                                 if data.dust then
292                                         --delete the data to speed up next loop
293                                         boundary[x][y][z] = nil
294                                 end
295                         end
296                 end
297         end
298
299         
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))
308                                 end
309                         end
310                 end
311         end
312 end
313
314
315 function redstone.inject(pos,data)
316         data_injection(pos,data)
317 end
318
319
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
325         end
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)
332                         redstone.update(pos)
333                 end)
334                 return
335         end
336
337         calculate(pos)
338 end
339
340 minetest.register_globalstep(function()
341         recursion_check = {}
342 end)
343
344
345 ----------------------------------------------------------------------------
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
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
387                         return
388                 end             
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)
393                         return
394                 end
395                 
396                 local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
397                 if worked then
398                         itemstack:take_item()
399                         return(itemstack)
400                 end
401
402
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})
406                         --return(itemstack)
407                 --end
408         end,
409 })
410
411 --8 power levels 8 being the highest
412 local color = 0
413 for i = 0,8 do
414         local coloring = floor(color)
415         minetest.register_node("redstone:dust_"..i,{
416                 description = "Redstone Dust",
417                 wield_image = "redstone_dust_item.png",
418                 tiles = {
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
421                 },
422                 power=i,
423                 drawtype = "raillike",
424                 paramtype = "light",
425                 sunlight_propagates = true,
426                 is_ground_content = false,
427                 walkable = false,
428                 node_placement_prediction = "",
429                 selection_box = {
430                         type = "fixed",
431                         fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
432                 },
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})
438                         calculate(pos)
439                 end,
440                 after_destruct = function(pos)
441                         data_injection(pos,nil)
442                         calculate(pos)
443                 end,
444                 connects_to = {"group:redstone"},
445         })
446         color= color +31.875
447
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})
454         end,
455     })
456 end