]> git.lizzy.rs Git - Crafter.git/blob - mods/redstone/init.lua
Allow activators to index redstone power metadata
[Crafter.git] / mods / redstone / init.lua
1 local 
2 minetest,vector,math,table,pairs
3 =
4 minetest,vector,math,table,pairs
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 local registered_nodes
16 minetest.register_on_mods_loaded(function()
17         registered_nodes  = minetest.registered_nodes
18 end)
19
20 -- math class
21 local abs   = math.abs
22 local floor = math.floor
23
24 -- vector library
25 local new_vec         = vector.new
26 local add_vec         = vector.add
27 local sub_vec         = vector.subtract
28 local vector_distance = vector.distance
29
30 -- redstone class
31 redstone = {}
32
33 local speed_test
34
35 local r_index = {}
36 local a_index = {}
37
38 local path = minetest.get_modpath("redstone")
39 dofile(path.."/functions.lua")
40 dofile(path.."/wire.lua")
41 dofile(path.."/torch.lua")
42 dofile(path.."/lever.lua")
43 dofile(path.."/button.lua")
44 dofile(path.."/repeater.lua")
45 dofile(path.."/light.lua")
46 dofile(path.."/piston.lua")
47 dofile(path.."/comparator.lua")
48 dofile(path.."/craft.lua")
49 dofile(path.."/ore.lua")
50 dofile(path.."/inverter.lua")
51 dofile(path.."/player_detector.lua")
52 dofile(path.."/space_maker.lua")
53 dofile(path.."/pressure_plate.lua")
54
55
56 --set the data for powered states
57 local get_local_power = function(pos)
58         if not pos then
59                 return
60         end
61         for x = -1,1 do
62         for y = -1,1 do
63         for z = -1,1 do
64                 --index only direct neighbors
65                 if abs(x)+abs(z)+abs(y) == 1 then
66                         --print(get_node(add_vec(new_vec(x,y,z),pos)).name)
67                         if get_item_group(get_node(add_vec(new_vec(x,y,z),pos)).name, "redstone_power") > 0 then
68                                 return(1)
69                         end
70                         if get_meta(add_vec(new_vec(x,y,z),pos)):get_int("redstone_power") > 0 then
71                                 return(1)
72                         end
73                 end
74         end
75         end
76         end     
77         return(0)
78 end
79
80 local power
81 local pos
82 local get_powered_state_directional = function(pos)
83         pos = sub_vec(pos,facedir_to_dir(get_node(pos).param2))
84         power = get_item_group(get_node(pos).name, "redstone_power")
85         if power == 0 then
86                 power = get_meta(pos):get_int("redstone_power")
87         end
88         return(power)
89 end
90
91 local node
92 local redstone_activate = function(pos,power)
93         after(0,function()
94                 node = get_node(pos).name
95                 if registered_nodes[node].redstone_activation then
96                         registered_nodes[node].redstone_activation(pos)
97                 end
98         end)
99 end
100
101 local node
102 local redstone_deactivate = function(pos,power)
103         after(0,function()
104                 node = get_node(pos).name
105                 if registered_nodes[node].redstone_deactivation then
106                         registered_nodes[node].redstone_deactivation(pos)
107                 end
108         end)
109 end
110
111 --collect all nodes that are local to the modified
112 --node of redstone dust and store in memory
113 local function get_group(i,gotten_group)
114         return(get_item_group(get_node(i).name, gotten_group))
115 end
116
117
118 local localredstone = {}
119
120 localredstone.injector = function(i)
121         if get_node(i).name == "air" then
122                 return
123         end
124
125         if r_index[i.x] and r_index[i.x][i.y] then
126                 if r_index[i.x][i.y][i.z] then
127                         return
128                 end
129         end
130
131         --index dust
132         if get_group(i,"redstone_dust") > 0 then
133                 --add data to both maps
134                 if not r_index[i.x] then r_index[i.x] = {} end
135                 if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
136                 r_index[i.x][i.y][i.z] = {dust = true,level = 0}
137                 --the data to the 3d array must be written to memory before this is executed
138                 --or a stack overflow occurs!!!
139                 localredstone.collector(i)
140         end
141         --index power sources
142         if get_group(i,"redstone_torch") > 0 then
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] = {torch = true,power=get_group(i,"redstone_power")}
146         end     
147         --index directional power sources (Like repeaters/comparators)
148         --only outputs forwards
149         if get_group(i,"torch_directional") > 0 then
150                 if not r_index[i.x] then r_index[i.x] = {} end
151                 if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
152                 r_index[i.x][i.y][i.z] = {torch_directional = true, dir = get_node(i).param2 , power = get_group(i,"redstone_power")}
153         end
154         
155         --index directional activators (Like repeaters/comparators)
156         --only accepts input from the back
157         if get_group(i,"redstone_activation_directional") > 0 then
158                 --print("indexing directional")
159                 if not a_index[i.x] then a_index[i.x] = {} end
160                 if not a_index[i.x][i.y] then a_index[i.x][i.y] = {} end
161                 if not a_index[i.x][i.y][i.z] then a_index[i.x][i.y][i.z] = {} end
162
163                 a_index[i.x][i.y][i.z].redstone_activation = true
164                 a_index[i.x][i.y][i.z].directional = true
165         end
166         
167         --index objects that activate
168         if get_group(i,"redstone_activation") > 0 then
169                 if not a_index[i.x] then a_index[i.x] = {} end
170                 if not a_index[i.x][i.y] then a_index[i.x][i.y] = {} end
171                 if not a_index[i.x][i.y][i.z] then a_index[i.x][i.y][i.z] = {} end
172                 a_index[i.x][i.y][i.z].redstone_activation = true
173         end
174
175         --sneaky way to make levers and buttons work
176         if get_meta(i):get_int("redstone_power") > 0 then
177                 if not r_index[i.x] then r_index[i.x] = {} end
178                 if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
179                 r_index[i.x][i.y][i.z] = {torch = true,power=get_meta(i):get_int("redstone_power")}
180         end
181 end
182
183 localredstone.collector = function(pos)
184         for x = -1,1 do
185         for y = -1,1 do
186         for z = -1,1 do
187                 if abs(x)+abs(z) == 1 then
188                         localredstone.injector(add_vec(pos,new_vec(x,y,z)))
189                 end
190         end
191         end
192         end
193 end
194
195
196 function redstone.collect_info(pos)
197         localredstone.injector(pos)
198         localredstone.collector(pos)
199 end
200
201
202 --check if index table contains items
203 --then execute an update
204 minetest.register_globalstep(function(dtime)
205         --if indexes exist then calculate redstone
206         if (r_index and next(r_index)) or (a_index and next(a_index)) then
207                 --create the old version to help with deactivation calculation
208                 redstone.calculate()
209                 --clear the index to avoid cpu looping wasting processing power
210                 r_index = {}
211                 a_index = {}
212         end
213 end)
214
215 --make all power sources push power out
216 local x_min
217 local x_max
218 local y_min
219 local y_max
220 local z_min
221 local z_max
222 local initial_check
223
224
225 local pos
226 local node
227 local power
228 function redstone.calculate()
229         speed_test = minetest.get_us_time()/1000000
230
231         --pathfind through memory map   
232         for x,index_x in pairs(r_index) do
233                 for y,index_y in pairs(index_x) do
234                         for z,data in pairs(index_y) do
235                                 --allow data values for torches
236                                 if data.torch then
237                                         redstone.pathfind(new_vec(x,y,z),data.power)
238                                         r_index[x][y][z] = nil
239                                 elseif data.torch_directional then
240                                         redstone.pathfind(new_vec(x,y,z),data.power,data.dir)
241                                         r_index[x][y][z] = nil
242                                 end
243                         end
244                 end
245         end
246         
247         print("total torch calc time:"..minetest.get_us_time()/1000000-speed_test)
248
249
250
251         --reassemble the table into a position list minetest can understand
252         --run through and set dust
253         for x,datax in pairs(r_index) do
254                 for y,datay in pairs(datax) do
255                         for z,index in pairs(datay) do
256                                 --print(get_node(new_vec(x,y,z)).name)
257                                 if index and index.dust then
258                                         minetest.set_node(new_vec(x,y,z),{name="redstone:dust_"..index.level})
259                                 end
260                         end
261                 end
262         end
263
264         for x,datax in pairs(a_index) do
265                 for y,datay in pairs(datax) do
266                         for z,index in pairs(datay) do
267                                 --directional activators
268                                 if index.directional == true then
269                                         power = get_powered_state_directional(new_vec(x,y,z))
270                                         if power then
271                                                 if power > 0 then
272                                                         redstone_activate(new_vec(x,y,z),power)
273                                                 elseif power == 0 then
274                                                         redstone_deactivate(new_vec(x,y,z),power)
275                                                 end
276                                         end
277                                 --non directional activators
278                                 else
279                                         power = get_local_power(new_vec(x,y,z))
280                                         if power then
281                                                 if power > 0 then
282                                                         redstone_activate(new_vec(x,y,z),power)
283                                                 elseif power == 0 then
284                                                         redstone_deactivate(new_vec(x,y,z),power)
285                                                 end
286                                         end
287                                 end
288                         end
289                 end
290         end
291 end
292
293 --make redstone wire pass on current one level lower than it is
294 local i
295 local index
296 local passed_on_level
297 local function redstone_pathfinder(source,source_level,direction)
298         --directional torches
299
300         if direction then
301                 --print("starting direction")
302                 i = add_vec(source,facedir_to_dir(direction))
303                 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
304                         index = r_index[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                                         r_index[i.x][i.y][i.z].level = passed_on_level
310                                         redstone_pathfinder(i,passed_on_level,nil,origin)
311                                 end
312                         end
313                 end
314         else
315                 --redstone and torch
316                 for x = -1,1 do
317                 for y = -1,1 do
318                 for z = -1,1 do
319                         if abs(x)+abs(z) == 1 then
320                                 i = add_vec(source,new_vec(x,y,z))
321                                 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
322                                         index = r_index[i.x][i.y][i.z]                                  
323                                         if index.dust  then
324                                                 passed_on_level = source_level - 1
325                                                 if passed_on_level > 0 and index.level < source_level then
326                                                         r_index[i.x][i.y][i.z].level = passed_on_level
327                                                         redstone_pathfinder(i,passed_on_level,nil)
328                                                 end
329                                         end
330                                 end
331                         end
332                 end
333                 end
334                 end
335         end
336 end
337 function redstone.pathfind(source,source_level,direction)
338         redstone_pathfinder(source,source_level,direction)
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
377
378
379
380
381
382 minetest.register_craftitem("redstone:dust", {
383         description = "Redstone Dust",
384         inventory_image = "redstone_dust_item.png",
385         wield_image = "redstone_dust_item.png",
386         wield_scale = {x = 1, y = 1, z = 1 + 1/16},
387         liquids_pointable = false,
388         on_place = function(itemstack, placer, pointed_thing)
389                 if not pointed_thing.type == "node" then
390                         return
391                 end             
392                 local sneak = placer:get_player_control().sneak
393                 local noddef = registered_nodes[get_node(pointed_thing.under).name]
394                 if not sneak and noddef.on_rightclick then
395                         minetest.item_place(itemstack, placer, pointed_thing)
396                         return
397                 end
398                 
399                 local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
400                 if worked then
401                         itemstack:take_item()
402                         return(itemstack)
403                 end
404
405
406                         --minetest.add_node(pointed_thing.above, {name="redstone:dust_0"})
407                         --itemstack:take_item(1)
408                         --minetest.sound_play("stone", {pos=pointed_thing.above})
409                         --return(itemstack)
410                 --end
411         end,
412 })
413
414 --8 power levels 8 being the highest
415 local color = 0
416 for i = 0,8 do
417         local coloring = floor(color)
418         minetest.register_node("redstone:dust_"..i,{
419                 description = "Redstone Dust",
420                 wield_image = "redstone_dust_item.png",
421                 tiles = {
422                         "redstone_dust_main.png^[colorize:red:"..coloring, "redstone_turn.png^[colorize:red:"..coloring,
423                         "redstone_t.png^[colorize:red:"..coloring, "redstone_cross.png^[colorize:red:"..coloring
424                 },
425                 power=i,
426                 drawtype = "raillike",
427                 paramtype = "light",
428                 sunlight_propagates = true,
429                 is_ground_content = false,
430                 walkable = false,
431                 node_placement_prediction = "",
432                 selection_box = {
433                         type = "fixed",
434                         fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
435                 },
436                 sounds = main.stoneSound(),
437                 groups={dig_immediate=1,attached_node=1,redstone_dust=1,redstone=1,redstone_power=i},
438                 drop="redstone:dust",
439                 on_construct = function(pos)
440                         redstone.collect_info(pos)
441                 end,
442                 after_destruct = function(pos)
443                         --redstone.remove(pos,registered_nodes[get_node(pos).name].power)
444                         redstone.collect_info(pos)
445                 end,
446                 connects_to = {"group:redstone"},
447         })
448         color= color +31.875
449 end