]> git.lizzy.rs Git - Crafter.git/blob - mods/redstone/init.lua
Add in colored redstone lights
[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         temp_pool = pool[pos.x][pos.y][pos.z]
145         for _,order in pairs(order) do
146                 n_pos = add_vec(pos,order)
147                 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
148                         temp_pool2 = pool[n_pos.x][n_pos.y][n_pos.z]
149                         if temp_pool2 then
150                                 if (not temp_pool2.directional_activator and temp_pool2.torch) or 
151                                 (temp_pool2.dust and temp_pool2.dust > 0) then
152                                         if activator_table[temp_pool.name].activate then
153                                                 activator_table[temp_pool.name].activate(pos)
154                                         end
155                                         return
156                                 end
157                         end
158                 end
159         end     
160         if activator_table[temp_pool.name].deactivate then
161                 activator_table[temp_pool.name].deactivate(pos)
162         end
163 end
164
165 -- directional activators
166 local n_pos
167 local temp_pool
168 local temp_pool2
169 local input
170 local ignore
171 local directional_activator = function(pos)
172         
173         ignore = false
174         input = nil
175         temp_pool2 = nil
176
177         temp_pool = pool[pos.x][pos.y][pos.z]
178         
179         if not temp_pool then ignore = true end
180
181         if not ignore then
182                 input = temp_pool.input
183         end
184
185         if not input then ignore = true end
186
187         if not ignore then
188                 input = temp_pool.input
189         end
190
191         if not ignore and pool and pool[input.x] and pool[input.x][input.y] and pool[input.x][input.y][input.z] then
192                 temp_pool2 = pool[input.x][input.y][input.z]
193         else
194                 ignore = true
195         end
196
197         if not temp_pool2 then ignore = true end
198
199         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 
200         (not temp_pool2.directional_activator and temp_pool2.torch))  then
201                 if activator_table[temp_pool.name].activate then
202                         activator_table[temp_pool.name].activate(pos)
203                         return
204                 end
205                 return
206         end
207
208         if activator_table[temp_pool.name].deactivate then
209                 activator_table[temp_pool.name].deactivate(pos)
210         end
211 end
212
213 --make redstone wire pass on current one level lower than it is
214 local i
215 local index
216 local passed_on_level
217 local function redstone_pathfinder(source,source_level,boundary,output)
218         if not source_level then return end
219         --directional torches
220         if output then
221                 i = output
222                 if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then
223                         index = boundary[i.x][i.y][i.z]
224                         --dust
225                         if index.dust then
226                                 passed_on_level = source_level - 1
227                                 if passed_on_level > 0 then
228                                         boundary[i.x][i.y][i.z].dust = passed_on_level
229                                         redstone_pathfinder(i,passed_on_level,boundary,nil)
230                                 end
231                         end
232                 end
233         else
234                 --redstone and torch
235                 for _,order in pairs(order) do
236                         i = add_vec(source,new_vec(order.x,order.y,order.z))
237                         if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then
238                                 index = boundary[i.x][i.y][i.z]
239                                 if index.dust then
240                                         passed_on_level = source_level - 1
241                                         if passed_on_level > 0 and index.dust < source_level then
242                                                 boundary[i.x][i.y][i.z].dust = passed_on_level
243                                                 redstone_pathfinder(i,passed_on_level,boundary,nil)
244                                         end
245                                 end
246                         end
247                 end
248         end
249         return(boundary)
250 end
251
252
253
254
255 --make all power sources push power out
256 local pos
257 local node
258 local power
259 local boundary
260 local function calculate(pos)
261         boundary = create_boundary_box(pos)
262         --pathfind through memory map   
263         for x,index_x in pairs(boundary) do
264                 for y,index_y in pairs(index_x) do
265                         for z,data in pairs(index_y) do
266                                 --allow data values for torches
267                                 if data.torch and not data.torch_directional then
268                                         redstone_pathfinder(new_vec(x,y,z),data.torch,boundary)
269                                         boundary[x][y][z] = nil
270                                 elseif data.torch_directional then
271                                         redstone_pathfinder(new_vec(x,y,z),data.torch,boundary,data.output)
272                                 end
273                         end
274                 end
275         end
276         --reassemble the table into a position list minetest can understand
277         --run through and set dust
278         for x,datax in pairs(boundary) do
279                 for y,datay in pairs(datax) do
280                         for z,data in pairs(datay) do
281                                 if data.dust and data.dust ~= data.origin then
282                                         swap_node(new_vec(x,y,z),{name="redstone:dust_"..data.dust})
283                                 end
284
285                                 --write data back to memory pool
286                                 pool[x][y][z] = data
287
288                                 if data.dust then
289                                         --delete the data to speed up next loop
290                                         boundary[x][y][z] = nil
291                                 end
292                         end
293                 end
294         end
295
296         
297         --this must be done after the memory is written
298         for x,datax in pairs(boundary) do
299                 for y,datay in pairs(datax) do
300                         for z,data in pairs(datay) do
301                                 if data.directional_activator then
302                                         directional_activator(new_vec(x,y,z))
303                                 elseif data.activator then
304                                         non_directional_activator(new_vec(x,y,z))
305                                 end
306                         end
307                 end
308         end
309 end
310
311
312 function redstone.inject(pos,data)
313         data_injection(pos,data)
314 end
315
316
317 local recursion_check = {}
318 function redstone.update(pos)
319         local s_pos = minetest.serialize(pos)
320         if not recursion_check[s_pos] then
321                 recursion_check[s_pos] = 0
322         end
323         recursion_check[s_pos] = recursion_check[s_pos] + 1
324         --print(recursion_check[s_pos])
325         if recursion_check[s_pos] > 6 then
326                 minetest.after(0,function()
327                         minetest.dig_node(pos)
328                         data_injection(pos,nil)
329                         redstone.update(pos)
330                 end)
331                 return
332         end
333
334         calculate(pos)
335 end
336
337 minetest.register_globalstep(function()
338         recursion_check = {}
339 end)
340
341
342 ----------------------------------------------------------------------------
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 minetest.register_craftitem("redstone:dust", {
377         description = "Redstone Dust",
378         inventory_image = "redstone_dust_item.png",
379         wield_image = "redstone_dust_item.png",
380         wield_scale = {x = 1, y = 1, z = 1 + 1/16},
381         liquids_pointable = false,
382         on_place = function(itemstack, placer, pointed_thing)
383                 if not pointed_thing.type == "node" then
384                         return
385                 end             
386                 local sneak = placer:get_player_control().sneak
387                 local noddef = registered_nodes[get_node(pointed_thing.under).name]
388                 if not sneak and noddef.on_rightclick then
389                         minetest.item_place(itemstack, placer, pointed_thing)
390                         return
391                 end
392                 
393                 local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
394                 if worked then
395                         itemstack:take_item()
396                         return(itemstack)
397                 end
398
399
400                         --minetest.add_node(pointed_thing.above, {name="redstone:dust_0"})
401                         --itemstack:take_item(1)
402                         --minetest.sound_play("stone", {pos=pointed_thing.above})
403                         --return(itemstack)
404                 --end
405         end,
406 })
407
408 --8 power levels 8 being the highest
409 local color = 0
410 for i = 0,8 do
411         local coloring = floor(color)
412         minetest.register_node("redstone:dust_"..i,{
413                 description = "Redstone Dust",
414                 wield_image = "redstone_dust_item.png",
415                 tiles = {
416                         "redstone_dust_main.png^[colorize:red:"..coloring, "redstone_turn.png^[colorize:red:"..coloring,
417                         "redstone_t.png^[colorize:red:"..coloring, "redstone_cross.png^[colorize:red:"..coloring
418                 },
419                 power=i,
420                 drawtype = "raillike",
421                 paramtype = "light",
422                 sunlight_propagates = true,
423                 is_ground_content = false,
424                 walkable = false,
425                 node_placement_prediction = "",
426                 selection_box = {
427                         type = "fixed",
428                         fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
429                 },
430                 sounds = main.stoneSound(),
431                 groups={dig_immediate=1,attached_node=1,redstone_dust=1,redstone=1,redstone_power=i},
432                 drop="redstone:dust",
433                 on_construct = function(pos)
434                         data_injection(pos,{dust=i})
435                         calculate(pos)
436                 end,
437                 after_destruct = function(pos)
438                         data_injection(pos,nil)
439                         calculate(pos)
440                 end,
441                 connects_to = {"group:redstone"},
442         })
443         color= color +31.875
444
445         minetest.register_lbm({
446         name = "redstone:"..i,
447                 nodenames = {"redstone:dust_"..i},
448                 run_at_every_load = true,
449         action = function(pos)
450             data_injection(pos,{dust=i})
451         end,
452     })
453 end