]> git.lizzy.rs Git - Crafter.git/blob - mods/redstone/init.lua
Stop player from dropping when they teleport through portals
[Crafter.git] / mods / redstone / init.lua
1 --define the class
2 redstone = {}
3 local r_index = {}
4
5 local path = minetest.get_modpath("redstone")
6 dofile(path.."/functions.lua")
7 dofile(path.."/wire.lua")
8 dofile(path.."/torch.lua")
9 dofile(path.."/lever.lua")
10 dofile(path.."/button.lua")
11 dofile(path.."/repeater.lua")
12 dofile(path.."/light.lua")
13 dofile(path.."/piston.lua")
14 dofile(path.."/comparator.lua")
15 dofile(path.."/craft.lua")
16 dofile(path.."/ore.lua")
17 dofile(path.."/inverter.lua")
18 dofile(path.."/player_detector.lua")
19 dofile(path.."/space_maker.lua")
20 dofile(path.."/pressure_plate.lua")
21
22
23 get_old_power = function(pos)
24         local meta = minetest.get_meta(pos)
25         local oldpower = meta:get_int("old_power")
26         return(oldpower)        
27 end
28 --set the data for powered states
29 get_local_power = function(pos)
30         local max_level = 0
31         for x = -1,1 do
32         for y = -1,1 do
33         for z = -1,1 do
34                 --index only direct neighbors
35                 if not (math.abs(x)+math.abs(z) > 1) or (math.abs(x)+math.abs(z) == 0) then
36                         --print(minetest.get_node(vector.add(vector.new(x,y,z),pos)).name)
37                         local level = minetest.get_node_group(minetest.get_node(vector.add(vector.new(x,y,z),pos)).name, "redstone_power")
38                         if level > max_level then
39                                 max_level = level
40                         end
41                 end
42         end
43         end
44         end     
45         return(max_level)
46 end
47
48 --this is used for a power state comparison
49 set_old_power = function(pos,level)
50         local meta = minetest.get_meta(pos)
51         meta:set_int("old_power",level)
52 end
53
54 get_powered_state_directional = function(pos)
55         local meta = minetest.get_meta(pos)
56         local node = minetest.get_node(pos)
57         local param2 = node.param2
58         local dir = minetest.facedir_to_dir(param2)
59         local input_pos = vector.subtract(pos,dir)
60         local behind_node = minetest.get_node(input_pos)
61         local level = minetest.get_node_group(behind_node.name, "redstone_power")
62         return(level)
63 end
64
65
66 local redstone_activate = function(name,pos,power)
67         minetest.after(0,function(name,pos)
68         if minetest.registered_nodes[name].redstone_activation then
69                 minetest.registered_nodes[name].redstone_activation(pos)
70         end
71         set_old_power(pos,power)
72         end,name,pos,power)
73 end
74
75 local redstone_deactivate = function(name,pos,power)
76         minetest.after(0,function(name,pos)
77         if minetest.registered_nodes[name].redstone_deactivation then
78                 minetest.registered_nodes[name].redstone_deactivation(pos)
79         end
80         set_old_power(pos,power)
81         end,name,pos,power)
82 end
83
84 local redstone_update = function(name,pos,power)
85         minetest.after(0,function(name,pos,power)
86         if minetest.registered_nodes[name].redstone_update then
87                 minetest.registered_nodes[name].redstone_update(pos)
88         end
89         set_old_power(pos,power)
90         end,name,pos,power)
91 end
92
93
94
95
96
97 --collect all nodes that are local to the modified
98 --node of redstone dust and store in memory
99 function redstone.collect_info(pos)
100         --if table.getn(r_index) == 0 then
101                 --print("-----------------------")
102                 --print("started indexing")
103         --end
104         local get_node = minetest.get_node 
105         local group = minetest.get_node_group
106         
107         local function get_group(i,gotten_group)
108                 return(group(get_node(i).name, gotten_group))
109         end
110         
111         for x = -1,1 do
112         for y = -1,1 do
113         for z = -1,1 do
114                 --index only direct neighbors
115                 if not (math.abs(x)+math.abs(z) > 1) or (math.abs(x)+math.abs(z) == 0) then
116                         local r_type = ""
117                         local i = vector.add(pos,vector.new(x,y,z))
118                         local execute_collection = true
119                         if r_index[i.x] and r_index[i.x][i.y] then
120                                 if r_index[i.x][i.y][i.z] then
121                                         execute_collection = false
122                                 end
123                         end
124                         --[[ EXPLANATION
125                                 we run through the groups
126                                 1 redstone_torch overrides dust if defined
127                                 2 torch_directional overrides torch if defined
128                                 3 redstone activation is bolted on with directional overriding general
129                                 
130                                 this is to prevent weird behavior
131                                 
132                                 
133                                 This new method also uses a table bolted onto the x,y,z positional data value
134                                 what does this mean?
135                                 It's much easier to work with and modify
136                         ]]--            
137                         
138                         if execute_collection == true then
139                                 --index dust
140                                 if get_group(i,"redstone_dust") > 0 then
141                                         --add data to both maps
142                                         if not r_index[i.x] then r_index[i.x] = {} end
143                                         if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
144                                         r_index[i.x][i.y][i.z] = {dust = true,level = 0} --get_group(i,"redstone_power")}                               
145                                         --the data to the 3d array must be written to memory before this is executed
146                                         --or a stack overflow occurs!!!
147                                         --pass down info for activators
148                                         redstone.collect_info(i,get_group(i,"redstone_power"))
149                                 end
150                                 --index power sources
151                                 if get_group(i,"redstone_torch") > 0 then
152                                         if not r_index[i.x] then r_index[i.x] = {} end
153                                         if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
154                                         r_index[i.x][i.y][i.z] = {torch = true,power=get_group(i,"redstone_power")}
155                                 end     
156                                 --index directional power sources (Like repeaters/comparators)
157                                 --only outputs forwards
158                                 if get_group(i,"torch_directional") > 0 then
159                                         if not r_index[i.x] then r_index[i.x] = {} end
160                                         if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
161                                         r_index[i.x][i.y][i.z] = {torch_directional = true, dir = get_node(i).param2 , power = get_group(i,"redstone_power")}
162                                 end
163                                 
164                                 --index directional activators (Like repeaters/comparators)
165                                 --only accepts input from the back
166                                 if get_group(i,"redstone_activation_directional") > 0 then
167                                         --print("indexing directional")
168                                         if not r_index[i.x] then r_index[i.x] = {} end
169                                         if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
170                                         if not r_index[i.x][i.y][i.z] then r_index[i.x][i.y][i.z] = {} end
171                                         --r_index[i.x][i.y][i.z].activate = false
172                                         r_index[i.x][i.y][i.z].redstone_activation = true
173                                         r_index[i.x][i.y][i.z].directional = true
174                                         r_index[i.x][i.y][i.z].dir = get_node(i).param2
175                                 end
176                                 
177                                 --index objects that activate
178                                 if get_group(i,"redstone_activation") > 0 then
179                                         if not r_index[i.x] then r_index[i.x] = {} end
180                                         if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end
181                                         if not r_index[i.x][i.y][i.z] then r_index[i.x][i.y][i.z] = {} end
182                                         --r_index[i.x][i.y][i.z].activate = false
183                                         r_index[i.x][i.y][i.z].redstone_activation = true
184                                         r_index[i.x][i.y][i.z].name = get_node(i).name
185                                         
186                                         
187                                         --set_powered_state(i)
188                                         
189                                         --local powered = get_powered_state(i)
190                                         
191                                         
192                                         --print("powered:"..powered,"oldpowered:"..old_powered)
193                                                                 
194                                         --r_index[i.x][i.y][i.z].powered = powered
195                                         --r_index[i.x][i.y][i.z].old_powered = old_powered
196                                         
197                                         --split this into update up and down
198                                         --if  powered > old_powered then
199                                         --      r_index[i.x][i.y][i.z].deactivate = true
200                                         ---elseif powered > 0 and old_powered == 0 then
201                                         --      r_index[i.x][i.y][i.z].deactivate = true
202                                         --end
203                                 end
204                         end
205                 end
206         end
207         end
208         end
209 end
210
211
212 --check if index table contains items
213 --then execute an update
214 minetest.register_globalstep(function(dtime)
215         --if indexes exist then calculate redstone
216         if r_index and next(r_index) then
217                 --create the old version to help with deactivation calculation
218                 r_copy = table.copy(r_index)
219                 redstone.calculate()
220         end
221         --clear the index to avoid cpu looping wasting processing power
222         r_index = {}
223 end)
224
225 --make all power sources push power out
226 function redstone.calculate()
227         --pathfind through memory map   
228         for x,index_x in pairs(r_index) do
229                 for y,index_y in pairs(index_x) do
230                         for z,data in pairs(index_y) do
231                                 --allow data values for torches
232                                 if data.torch then
233                                         redstone.pathfind(vector.new(x,y,z),data.power)
234                                 elseif data.torch_directional then
235                                         redstone.pathfind(vector.new(x,y,z),data.power,data.dir)
236                                 end
237                         end
238                 end
239         end
240                 
241         --calculate values for voxel manip
242         local x_min,x_max,y_min,y_max,z_min,z_max
243         for x,index_x in pairs(r_index) do
244                 for y,index_y in pairs(index_x) do
245                         for z,_ in pairs(index_y) do
246                                 --do this because the root (x) will always come first
247                                 if not x_min then
248                                         x_min = x
249                                         x_max = x
250                                         y_min = y
251                                         y_max = y
252                                         z_min = z
253                                         z_max = z
254                                 end
255                                 if x < x_min then x_min = x end
256                                 if x > x_max then x_max = x end
257                                 if y < y_min then y_min = y end
258                                 if y > y_max then y_max = y end
259                                 if z < z_min then z_min = z end
260                                 if z > z_max then z_max = z end
261                         end
262                 end
263         end
264
265         local min = vector.new(x_min,y_min,z_min)
266         local max = vector.new(x_max,y_max,z_max)
267         local vm = minetest.get_voxel_manip()   
268         local emin, emax = vm:read_from_map(min,max)
269         local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
270         local data = vm:get_data()
271         local content_id = minetest.get_name_from_content_id
272         --reassemble the table into a position list minetest can understand
273         
274         --run through and set dust
275         for x,datax in pairs(r_index) do
276                 for y,datay in pairs(datax) do
277                         for z,index in pairs(datay) do
278                                 local p_pos = area:index(x,y,z) 
279                                 if index.dust then
280                                         data[p_pos] = minetest.get_content_id("redstone:dust_"..index.level)
281                                 end
282                         end
283                 end
284         end
285         vm:set_data(data)
286         vm:write_to_map()
287         
288         
289         
290         --run through activators
291         for x,datax in pairs(r_index) do
292                 for y,datay in pairs(datax) do
293                         for z,index in pairs(datay) do
294                                 local pos = vector.new(x,y,z)
295                                 local node = minetest.get_node(pos)
296                                 --directional activators
297                                 if index.redstone_activation == true and index.directional == true then
298                                         local power = get_powered_state_directional(pos)
299                                         local old_power = get_old_power(pos)
300                                         if power > 0 and old_power == 0 then
301                                                 redstone_activate(node.name,pos,power)
302                                         elseif power == 0 and old_power > 0 then
303                                                 redstone_deactivate(node.name,pos,power)
304                                         --do an update if state has not changed
305                                         elseif power > 0 and old_power > 0 then
306                                                 redstone_update(node.name,pos,power)
307                                         elseif power == 0 and old_power == 0 then
308                                                 redstone_update(node.name,pos,power)
309                                         end
310                                 --non directional activators
311                                 elseif index.redstone_activation == true then
312                                         local power = get_local_power(pos)
313                                         local old_power = get_old_power(pos)
314                                         if power > 0 and old_power == 0 then
315                                                 redstone_activate(node.name,pos,power)
316                                         elseif power == 0 and old_power > 0 then
317                                                 redstone_deactivate(node.name,pos,power)
318                                         --do an update if state has not changed
319                                         elseif power > 0 and old_power > 0 then
320                                                 redstone_update(node.name,pos,power)
321                                         elseif power == 0 and old_power == 0 then
322                                                 redstone_update(node.name,pos,power)
323                                         end
324                                 end
325                         end
326                 end
327         end
328 end
329
330 --make redstone wire pass on current one level lower than it is
331 function redstone.pathfind(source,source_level,direction)
332         --directional torches
333         if direction then
334                 --print("starting direction")
335                 local dir = minetest.facedir_to_dir(direction)
336                 local i = vector.add(source,dir)
337                 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
338                         local index = r_index[i.x][i.y][i.z]
339                         --dust
340                         if index.dust  then
341                                 local passed_on_level = source_level - 1
342                                 if passed_on_level > 0 then
343                                         r_index[i.x][i.y][i.z].level = passed_on_level
344                                         redstone.pathfind(i,passed_on_level)
345                                 end
346                         end
347                 end
348         else
349                 --redstone and torch
350                 for x = -1,1 do
351                 for y = -1,1 do
352                 for z = -1,1 do
353                         local i = vector.add(source,vector.new(x,y,z))
354                         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
355                                 local index = r_index[i.x][i.y][i.z]                                    
356                                 if index.dust  then
357                                         local passed_on_level = source_level - 1
358                                         if passed_on_level > 0 and index.level < source_level then
359                                                 r_index[i.x][i.y][i.z].level = passed_on_level
360                                                 redstone.pathfind(i,passed_on_level)
361                                         end
362                                 end
363                         end
364                 end
365                 end
366                 end
367         end
368 end
369
370
371
372
373
374
375
376
377 ----------------------------------------------------------------------------
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411 minetest.register_craftitem("redstone:dust", {
412         description = "Redstone Dust",
413         inventory_image = "redstone_dust_item.png",
414         wield_image = "redstone_dust_item.png",
415         wield_scale = {x = 1, y = 1, z = 1 + 1/16},
416         liquids_pointable = false,
417         on_place = function(itemstack, placer, pointed_thing)
418                 if not pointed_thing.type == "node" then
419                         return
420                 end             
421                 local sneak = placer:get_player_control().sneak
422                 local noddef = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name]
423                 if not sneak and noddef.on_rightclick then
424                         minetest.item_place(itemstack, placer, pointed_thing)
425                         return
426                 end
427                 
428                 local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
429                 if worked then
430                         itemstack:take_item()
431                         return(itemstack)
432                 end
433
434
435                         --minetest.add_node(pointed_thing.above, {name="redstone:dust_0"})
436                         --itemstack:take_item(1)
437                         --minetest.sound_play("stone", {pos=pointed_thing.above})
438                         --return(itemstack)
439                 --end
440         end,
441 })
442
443 minetest.register_craft({
444         type = "shapeless",
445         output = "redstone:dust",
446         recipe = {"redstone:dust"},
447 })
448
449 --8 power levels 8 being the highest
450 local color = 0
451 for i = 0,8 do
452         local coloring = math.floor(color)
453         minetest.register_node("redstone:dust_"..i,{
454                 description = "Redstone Dust",
455                 wield_image = "redstone_dust_item.png",
456                 tiles = {
457                         "redstone_dust_main.png^[colorize:red:"..coloring, "redstone_turn.png^[colorize:red:"..coloring,
458                         "redstone_t.png^[colorize:red:"..coloring, "redstone_cross.png^[colorize:red:"..coloring
459                 },
460                 power=i,
461                 drawtype = "raillike",
462                 paramtype = "light",
463                 sunlight_propagates = true,
464                 is_ground_content = false,
465                 walkable = false,
466                 node_placement_prediction = "",
467                 selection_box = {
468                         type = "fixed",
469                         fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
470                 },
471                 sounds = main.stoneSound(),
472                 groups={dig_immediate=1,attached_node=1,redstone_dust=1,redstone=1,redstone_power=i},
473                 drop="redstone:dust",
474                 on_construct = function(pos)
475                         redstone.collect_info(pos)
476                 end,
477                 after_destruct = function(pos)
478                         --redstone.remove(pos,minetest.registered_nodes[minetest.get_node(pos).name].power)
479                         redstone.collect_info(pos,i)
480                 end,
481                 connects_to = {"group:redstone"},
482         })
483         color= color +31.875
484 end