forked from minetest-mods/mesecons
		
	Compare commits
	
		
			11 Commits
		
	
	
		
			numzero-fi
			...
			e1cffdedbf
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e1cffdedbf | ||
| 
						 | 
					d3aedd2b98 | ||
| 
						 | 
					68c1729990 | ||
| 
						 | 
					9b58f8db29 | ||
| 
						 | 
					7784b13da5 | ||
| 
						 | 
					0dd530312b | ||
| 
						 | 
					e78bbd6f98 | ||
| 
						 | 
					bfd952b51a | ||
| 
						 | 
					b7873e8e02 | ||
| 
						 | 
					d6b2a39c99 | ||
| 
						 | 
					1b54011b68 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +1,3 @@
 | 
			
		||||
*~
 | 
			
		||||
*.patch
 | 
			
		||||
*.diff
 | 
			
		||||
 
 | 
			
		||||
@@ -1,96 +1,140 @@
 | 
			
		||||
mesecon.queue.actions={} -- contains all ActionQueue actions
 | 
			
		||||
--[[
 | 
			
		||||
Mesecons uses something it calls an ActionQueue.
 | 
			
		||||
 | 
			
		||||
function mesecon.queue:add_function(name, func)
 | 
			
		||||
	mesecon.queue.funcs[name] = func
 | 
			
		||||
The ActionQueue holds functions and actions.
 | 
			
		||||
Functions are added on load time with a specified name.
 | 
			
		||||
Actions are preserved over server restarts.
 | 
			
		||||
 | 
			
		||||
Each action consists of a position, the name of an added function to be called,
 | 
			
		||||
the params that should be used in this function call (additionally to the pos),
 | 
			
		||||
the time after which it should be executed, an optional overwritecheck and a
 | 
			
		||||
priority.
 | 
			
		||||
 | 
			
		||||
If time = 0, the action will be executed in the next globalstep, otherwise the
 | 
			
		||||
earliest globalstep when it will be executed is the after next globalstep.
 | 
			
		||||
 | 
			
		||||
It is guaranteed, that for two actions ac1, ac2 where ac1 ~= ac2,
 | 
			
		||||
ac1.time == ac2.time, ac1.priority == ac2.priority and ac1 was added earlier
 | 
			
		||||
than ac2, ac1 will be executed before ac2 (but in the same globalstep).
 | 
			
		||||
 | 
			
		||||
Note: Do not pass references in params, as they can not be preserved.
 | 
			
		||||
 | 
			
		||||
Also note: Some of the guarantees here might be dropped at some time.
 | 
			
		||||
]]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- localize for speed
 | 
			
		||||
local queue = mesecon.queue
 | 
			
		||||
 | 
			
		||||
queue.actions = {} -- contains all ActionQueue actions
 | 
			
		||||
 | 
			
		||||
function queue:add_function(name, func)
 | 
			
		||||
	queue.funcs[name] = func
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten
 | 
			
		||||
-- use overwritecheck nil to never overwrite, but just add the event to the queue
 | 
			
		||||
-- priority specifies the order actions are executed within one globalstep, highest first
 | 
			
		||||
-- should be between 0 and 1
 | 
			
		||||
function mesecon.queue:add_action(pos, func, params, time, overwritecheck, priority)
 | 
			
		||||
function queue:add_action(pos, func, params, time, overwritecheck, priority)
 | 
			
		||||
	-- Create Action Table:
 | 
			
		||||
	time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution
 | 
			
		||||
	priority = priority or 1
 | 
			
		||||
	local action = {	pos=mesecon.tablecopy(pos),
 | 
			
		||||
				func=func,
 | 
			
		||||
				params=mesecon.tablecopy(params or {}),
 | 
			
		||||
				time=time,
 | 
			
		||||
				owcheck=(overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
 | 
			
		||||
				priority=priority}
 | 
			
		||||
	local action = {
 | 
			
		||||
		pos = mesecon.tablecopy(pos),
 | 
			
		||||
		func = func,
 | 
			
		||||
		params = mesecon.tablecopy(params or {}),
 | 
			
		||||
		time = time,
 | 
			
		||||
		owcheck = (overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
 | 
			
		||||
		priority = priority
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	local toremove = nil
 | 
			
		||||
	-- Otherwise, add the action to the queue
 | 
			
		||||
	if overwritecheck then -- check if old action has to be overwritten / removed:
 | 
			
		||||
		for i, ac in ipairs(mesecon.queue.actions) do
 | 
			
		||||
			if(vector.equals(pos, ac.pos)
 | 
			
		||||
			and mesecon.cmpAny(overwritecheck, ac.owcheck)) then
 | 
			
		||||
				toremove = i
 | 
			
		||||
	 -- check if old action has to be overwritten / removed:
 | 
			
		||||
	if overwritecheck then
 | 
			
		||||
		for i, ac in ipairs(queue.actions) do
 | 
			
		||||
			if vector.equals(pos, ac.pos)
 | 
			
		||||
					and mesecon.cmpAny(overwritecheck, ac.owcheck) then
 | 
			
		||||
				-- remove the old action
 | 
			
		||||
				table.remove(queue.actions, i)
 | 
			
		||||
				break
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	if (toremove ~= nil) then
 | 
			
		||||
		table.remove(mesecon.queue.actions, toremove)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	table.insert(mesecon.queue.actions, action)
 | 
			
		||||
	table.insert(queue.actions, action)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- execute the stored functions on a globalstep
 | 
			
		||||
-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function
 | 
			
		||||
-- this makes sure that resuming mesecons circuits when restarting minetest works fine
 | 
			
		||||
-- this makes sure that resuming mesecons circuits when restarting minetest works fine (hm, where do we do this?)
 | 
			
		||||
-- However, even that does not work in some cases, that's why we delay the time the globalsteps
 | 
			
		||||
-- start to be execute by 5 seconds
 | 
			
		||||
local get_highest_priority = function (actions)
 | 
			
		||||
	local highestp = -1
 | 
			
		||||
	local highesti
 | 
			
		||||
	for i, ac in ipairs(actions) do
 | 
			
		||||
		if ac.priority > highestp then
 | 
			
		||||
			highestp = ac.priority
 | 
			
		||||
			highesti = i
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
-- start to be execute by 4 seconds
 | 
			
		||||
 | 
			
		||||
	return highesti
 | 
			
		||||
end
 | 
			
		||||
local function globalstep_func(dtime)
 | 
			
		||||
	local actions = queue.actions
 | 
			
		||||
	-- split into two categories:
 | 
			
		||||
	-- actions_now: actions to execute now
 | 
			
		||||
	-- queue.actions: actions to execute later
 | 
			
		||||
	local actions_now = {}
 | 
			
		||||
	queue.actions = {}
 | 
			
		||||
 | 
			
		||||
local m_time = 0
 | 
			
		||||
local resumetime = mesecon.setting("resumetime", 4)
 | 
			
		||||
minetest.register_globalstep(function (dtime)
 | 
			
		||||
	m_time = m_time + dtime
 | 
			
		||||
	-- don't even try if server has not been running for XY seconds; resumetime = time to wait
 | 
			
		||||
	-- after starting the server before processing the ActionQueue, don't set this too low
 | 
			
		||||
	if (m_time < resumetime) then return end
 | 
			
		||||
	local actions = mesecon.tablecopy(mesecon.queue.actions)
 | 
			
		||||
	local actions_now={}
 | 
			
		||||
 | 
			
		||||
	mesecon.queue.actions = {}
 | 
			
		||||
 | 
			
		||||
	-- sort actions into two categories:
 | 
			
		||||
	-- those toexecute now (actions_now) and those to execute later (mesecon.queue.actions)
 | 
			
		||||
	for i, ac in ipairs(actions) do
 | 
			
		||||
	for _, ac in ipairs(actions) do
 | 
			
		||||
		if ac.time > 0 then
 | 
			
		||||
			ac.time = ac.time - dtime -- executed later
 | 
			
		||||
			table.insert(mesecon.queue.actions, ac)
 | 
			
		||||
			-- action ac is to be executed later
 | 
			
		||||
			-- ~> insert into queue.actions
 | 
			
		||||
			ac.time = ac.time - dtime
 | 
			
		||||
			table.insert(queue.actions, ac)
 | 
			
		||||
		else
 | 
			
		||||
			-- action ac is to be executed now
 | 
			
		||||
			-- ~> insert into actions_now
 | 
			
		||||
			table.insert(actions_now, ac)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	while(#actions_now > 0) do -- execute highest priorities first, until all are executed
 | 
			
		||||
		local hp = get_highest_priority(actions_now)
 | 
			
		||||
		mesecon.queue:execute(actions_now[hp])
 | 
			
		||||
		table.remove(actions_now, hp)
 | 
			
		||||
	-- stable-sort the executed actions after their priority
 | 
			
		||||
	-- some constructions might depend on the execution order, hence we first
 | 
			
		||||
	-- execute the actions that had a lower index in actions_now
 | 
			
		||||
	local old_action_order = {}
 | 
			
		||||
	for i, ac in ipairs(actions_now) do
 | 
			
		||||
		old_action_order[ac] = i
 | 
			
		||||
	end
 | 
			
		||||
end)
 | 
			
		||||
	table.sort(actions_now, function(ac1, ac2)
 | 
			
		||||
		if ac1.priority ~= ac2.priority then
 | 
			
		||||
			return ac1.priority > ac2.priority
 | 
			
		||||
		else
 | 
			
		||||
			return old_action_order[ac1] < old_action_order[ac2]
 | 
			
		||||
		end
 | 
			
		||||
	end)
 | 
			
		||||
 | 
			
		||||
function mesecon.queue:execute(action)
 | 
			
		||||
	-- execute highest priorities first, until all are executed
 | 
			
		||||
	for _, ac in ipairs(actions_now) do
 | 
			
		||||
		queue:execute(ac)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- delay the time the globalsteps start to be execute by 4 seconds
 | 
			
		||||
do
 | 
			
		||||
	local m_time = 0
 | 
			
		||||
	local resumetime = mesecon.setting("resumetime", 4)
 | 
			
		||||
	local globalstep_func_index = #minetest.registered_globalsteps + 1
 | 
			
		||||
 | 
			
		||||
	minetest.register_globalstep(function(dtime)
 | 
			
		||||
		m_time = m_time + dtime
 | 
			
		||||
		-- don't even try if server has not been running for XY seconds; resumetime = time to wait
 | 
			
		||||
		-- after starting the server before processing the ActionQueue, don't set this too low
 | 
			
		||||
		if m_time < resumetime then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		-- replace this globalstep function
 | 
			
		||||
		minetest.registered_globalsteps[globalstep_func_index] = globalstep_func
 | 
			
		||||
	end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function queue:execute(action)
 | 
			
		||||
	-- ignore if action queue function name doesn't exist,
 | 
			
		||||
	-- (e.g. in case the action queue savegame was written by an old mesecons version)
 | 
			
		||||
	if mesecon.queue.funcs[action.func] then
 | 
			
		||||
		mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
 | 
			
		||||
	if queue.funcs[action.func] then
 | 
			
		||||
		queue.funcs[action.func](action.pos, unpack(action.params))
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@@ -98,8 +142,8 @@ end
 | 
			
		||||
-- Store and read the ActionQueue to / from a file
 | 
			
		||||
-- so that upcoming actions are remembered when the game
 | 
			
		||||
-- is restarted
 | 
			
		||||
mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
 | 
			
		||||
queue.actions = mesecon.file2table("mesecon_actionqueue")
 | 
			
		||||
 | 
			
		||||
minetest.register_on_shutdown(function()
 | 
			
		||||
	mesecon.table2file("mesecon_actionqueue", mesecon.queue.actions)
 | 
			
		||||
	mesecon.table2file("mesecon_actionqueue", queue.actions)
 | 
			
		||||
end)
 | 
			
		||||
 
 | 
			
		||||
@@ -186,19 +186,11 @@ function mesecon.invertRule(r)
 | 
			
		||||
	return vector.multiply(r, -1)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon.tablecopy(table) -- deep table copy
 | 
			
		||||
	if type(table) ~= "table" then return table end -- no need to copy
 | 
			
		||||
	local newtable = {}
 | 
			
		||||
 | 
			
		||||
	for idx, item in pairs(table) do
 | 
			
		||||
		if type(item) == "table" then
 | 
			
		||||
			newtable[idx] = mesecon.tablecopy(item)
 | 
			
		||||
		else
 | 
			
		||||
			newtable[idx] = item
 | 
			
		||||
function mesecon.tablecopy(obj) -- deep copy
 | 
			
		||||
	if type(obj) == "table" then
 | 
			
		||||
		return table.copy(obj)
 | 
			
		||||
	end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	return newtable
 | 
			
		||||
	return obj
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function mesecon.cmpAny(t1, t2)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,19 +33,9 @@ end
 | 
			
		||||
 | 
			
		||||
-- Register the 2 (states) x 4 (delay times) delayers
 | 
			
		||||
 | 
			
		||||
for i = 1, 4 do
 | 
			
		||||
local groups = {}
 | 
			
		||||
if i == 1 then
 | 
			
		||||
	groups = {bendy=2,snappy=1,dig_immediate=2}
 | 
			
		||||
else
 | 
			
		||||
	groups = {bendy=2,snappy=1,dig_immediate=2, not_in_creative_inventory=1}
 | 
			
		||||
end
 | 
			
		||||
local delaytime = { 0.1, 0.3, 0.5, 1.0 }
 | 
			
		||||
 | 
			
		||||
local delaytime
 | 
			
		||||
if 		i == 1 then delaytime = 0.1
 | 
			
		||||
elseif	i == 2 then delaytime = 0.3
 | 
			
		||||
elseif	i == 3 then delaytime = 0.5
 | 
			
		||||
elseif	i == 4 then delaytime = 1.0 end
 | 
			
		||||
for i = 1, 4 do
 | 
			
		||||
 | 
			
		||||
local boxes = {
 | 
			
		||||
	 { -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 },		-- the main slab
 | 
			
		||||
@@ -61,9 +51,36 @@ local boxes = {
 | 
			
		||||
	 { 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
 | 
			
		||||
	description = "Delayer",
 | 
			
		||||
-- Delayer definition defaults
 | 
			
		||||
local def = {
 | 
			
		||||
	drawtype = "nodebox",
 | 
			
		||||
	walkable = true,
 | 
			
		||||
	selection_box = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
 | 
			
		||||
	},
 | 
			
		||||
	node_box = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = boxes
 | 
			
		||||
	},
 | 
			
		||||
	paramtype = "light",
 | 
			
		||||
	paramtype2 = "facedir",
 | 
			
		||||
	sunlight_propagates = true,
 | 
			
		||||
	is_ground_content = false,
 | 
			
		||||
	delayer_time = delaytime[i],
 | 
			
		||||
	sounds = default.node_sound_stone_defaults(),
 | 
			
		||||
	on_blast = mesecon.on_blastnode,
 | 
			
		||||
	drop = "mesecons_delayer:delayer_off_1",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
-- Deactivated delayer definition defaults
 | 
			
		||||
local off_groups = {bendy=2,snappy=1,dig_immediate=2}
 | 
			
		||||
if i > 1 then
 | 
			
		||||
	off_groups.not_in_creative_inventory = 1
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local off_state = {
 | 
			
		||||
	description = "Delayer",
 | 
			
		||||
	tiles = {
 | 
			
		||||
		"mesecons_delayer_off_"..tostring(i)..".png",
 | 
			
		||||
		"mesecons_delayer_bottom.png",
 | 
			
		||||
@@ -74,35 +91,18 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
 | 
			
		||||
	},
 | 
			
		||||
	inventory_image = "mesecons_delayer_off_1.png",
 | 
			
		||||
	wield_image = "mesecons_delayer_off_1.png",
 | 
			
		||||
	walkable = true,
 | 
			
		||||
	selection_box = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
 | 
			
		||||
	},
 | 
			
		||||
	node_box = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = boxes
 | 
			
		||||
	},
 | 
			
		||||
	groups = groups,
 | 
			
		||||
	paramtype = "light",
 | 
			
		||||
	paramtype2 = "facedir",
 | 
			
		||||
	sunlight_propagates = true,
 | 
			
		||||
	is_ground_content = false,
 | 
			
		||||
	drop = 'mesecons_delayer:delayer_off_1',
 | 
			
		||||
	on_punch = function (pos, node)
 | 
			
		||||
		if node.name=="mesecons_delayer:delayer_off_1" then
 | 
			
		||||
			minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_2", param2=node.param2})
 | 
			
		||||
		elseif node.name=="mesecons_delayer:delayer_off_2" then
 | 
			
		||||
			minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_3", param2=node.param2})
 | 
			
		||||
		elseif node.name=="mesecons_delayer:delayer_off_3" then
 | 
			
		||||
			minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_4", param2=node.param2})
 | 
			
		||||
		elseif node.name=="mesecons_delayer:delayer_off_4" then
 | 
			
		||||
			minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_1", param2=node.param2})
 | 
			
		||||
	groups = off_groups,
 | 
			
		||||
	on_punch = function(pos, node, puncher)
 | 
			
		||||
		if minetest.is_protected(pos, puncher and puncher:get_player_name()) then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		minetest.swap_node(pos, {
 | 
			
		||||
			name = "mesecons_delayer:delayer_off_"..tostring(i % 4 + 1),
 | 
			
		||||
			param2 = node.param2
 | 
			
		||||
		})
 | 
			
		||||
	end,
 | 
			
		||||
	delayer_time = delaytime,
 | 
			
		||||
	delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i),
 | 
			
		||||
	sounds = default.node_sound_stone_defaults(),
 | 
			
		||||
	mesecons = {
 | 
			
		||||
		receptor =
 | 
			
		||||
		{
 | 
			
		||||
@@ -115,13 +115,15 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
 | 
			
		||||
			action_on = delayer_activate
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	on_blast = mesecon.on_blastnode,
 | 
			
		||||
})
 | 
			
		||||
}
 | 
			
		||||
for k, v in pairs(def) do
 | 
			
		||||
	off_state[k] = off_state[k] or v
 | 
			
		||||
end
 | 
			
		||||
minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), off_state)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
 | 
			
		||||
-- Activated delayer definition defaults
 | 
			
		||||
local on_state = {
 | 
			
		||||
	description = "You hacker you",
 | 
			
		||||
	drawtype = "nodebox",
 | 
			
		||||
	tiles = {
 | 
			
		||||
		"mesecons_delayer_on_"..tostring(i)..".png",
 | 
			
		||||
		"mesecons_delayer_bottom.png",
 | 
			
		||||
@@ -130,35 +132,18 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
 | 
			
		||||
		"mesecons_delayer_sides_on.png",
 | 
			
		||||
		"mesecons_delayer_sides_on.png"
 | 
			
		||||
	},
 | 
			
		||||
	walkable = true,
 | 
			
		||||
	selection_box = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
 | 
			
		||||
	},
 | 
			
		||||
	node_box = {
 | 
			
		||||
		type = "fixed",
 | 
			
		||||
		fixed = boxes
 | 
			
		||||
	},
 | 
			
		||||
	groups = {bendy = 2, snappy = 1, dig_immediate = 2, not_in_creative_inventory = 1},
 | 
			
		||||
	paramtype = "light",
 | 
			
		||||
	paramtype2 = "facedir",
 | 
			
		||||
	sunlight_propagates = true,
 | 
			
		||||
	is_ground_content = false,
 | 
			
		||||
	drop = 'mesecons_delayer:delayer_off_1',
 | 
			
		||||
	on_punch = function (pos, node)
 | 
			
		||||
		if node.name=="mesecons_delayer:delayer_on_1" then
 | 
			
		||||
			minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_2", param2=node.param2})
 | 
			
		||||
		elseif node.name=="mesecons_delayer:delayer_on_2" then
 | 
			
		||||
			minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_3", param2=node.param2})
 | 
			
		||||
		elseif node.name=="mesecons_delayer:delayer_on_3" then
 | 
			
		||||
			minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_4", param2=node.param2})
 | 
			
		||||
		elseif node.name=="mesecons_delayer:delayer_on_4" then
 | 
			
		||||
			minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_1", param2=node.param2})
 | 
			
		||||
	on_punch = function(pos, node, puncher)
 | 
			
		||||
		if minetest.is_protected(pos, puncher and puncher:get_player_name()) then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		minetest.swap_node(pos, {
 | 
			
		||||
			name = "mesecons_delayer:delayer_on_"..tostring(i % 4 + 1),
 | 
			
		||||
			param2 = node.param2
 | 
			
		||||
		})
 | 
			
		||||
	end,
 | 
			
		||||
	delayer_time = delaytime,
 | 
			
		||||
	delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i),
 | 
			
		||||
	sounds = default.node_sound_stone_defaults(),
 | 
			
		||||
	mesecons = {
 | 
			
		||||
		receptor =
 | 
			
		||||
		{
 | 
			
		||||
@@ -171,8 +156,12 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
 | 
			
		||||
			action_off = delayer_deactivate
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	on_blast = mesecon.on_blastnode,
 | 
			
		||||
})
 | 
			
		||||
}
 | 
			
		||||
for k, v in pairs(def) do
 | 
			
		||||
	on_state[k] = on_state[k] or v
 | 
			
		||||
end
 | 
			
		||||
minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), on_state)
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
minetest.register_craft({
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,11 @@
 | 
			
		||||
local plg = {}
 | 
			
		||||
plg.rules = {}
 | 
			
		||||
-- per-player formspec positions
 | 
			
		||||
plg.open_formspecs = {}
 | 
			
		||||
 | 
			
		||||
local lcore = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/logic.lua")
 | 
			
		||||
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/tool.lua")(plg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
plg.register_nodes = function(template)
 | 
			
		||||
	-- each loop is for one of the 4 IO ports
 | 
			
		||||
	for a = 0, 1 do
 | 
			
		||||
@@ -93,16 +94,20 @@ plg.register_nodes({
 | 
			
		||||
 | 
			
		||||
		meta:set_string("instr", lcore.serialize(is))
 | 
			
		||||
		meta:set_int("valid", 0)
 | 
			
		||||
		meta:set_string("formspec", plg.to_formspec_string(is))
 | 
			
		||||
		meta:set_string("infotext", "FPGA")
 | 
			
		||||
	end,
 | 
			
		||||
	on_receive_fields = function(pos, formname, fields, sender)
 | 
			
		||||
		if fields.program == nil then return end -- we only care when the user clicks "Program"
 | 
			
		||||
	on_rightclick = function(pos, node, clicker)
 | 
			
		||||
		if not minetest.is_player(clicker) then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		local meta = minetest.get_meta(pos)
 | 
			
		||||
		local is = plg.from_formspec_fields(fields)
 | 
			
		||||
		local name = clicker:get_player_name()
 | 
			
		||||
		-- Erase formspecs of old FPGAs
 | 
			
		||||
		meta:set_string("formspec", "")
 | 
			
		||||
 | 
			
		||||
		meta:set_string("instr", lcore.serialize(is))
 | 
			
		||||
		plg.update_formspec(pos, is)
 | 
			
		||||
		plg.open_formspecs[name] = pos
 | 
			
		||||
		local is = lcore.deserialize(meta:get_string("instr"))
 | 
			
		||||
		minetest.show_formspec(name, "mesecons:fpga", plg.to_formspec_string(is, nil))
 | 
			
		||||
	end,
 | 
			
		||||
	sounds = default.node_sound_stone_defaults(),
 | 
			
		||||
	mesecons = {
 | 
			
		||||
@@ -116,6 +121,12 @@ plg.register_nodes({
 | 
			
		||||
	},
 | 
			
		||||
	after_dig_node = function(pos, node)
 | 
			
		||||
		mesecon.receptor_off(pos, plg.rules[node.name])
 | 
			
		||||
		for name, open_pos in pairs(plg.open_formspecs) do
 | 
			
		||||
			if vector.equals(pos, open_pos) then
 | 
			
		||||
				minetest.close_formspec(name, "mesecons:fpga")
 | 
			
		||||
				plg.open_formspecs[name] = nil
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end,
 | 
			
		||||
	on_blast = mesecon.on_blastnode,
 | 
			
		||||
	on_rotate = function(pos, node, user, mode)
 | 
			
		||||
@@ -153,13 +164,12 @@ plg.register_nodes({
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		meta:set_string("instr", lcore.serialize(instr))
 | 
			
		||||
		plg.update_formspec(pos, instr)
 | 
			
		||||
		plg.update_meta(pos, instr)
 | 
			
		||||
		return true
 | 
			
		||||
	end,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
plg.to_formspec_string = function(is)
 | 
			
		||||
plg.to_formspec_string = function(is, err)
 | 
			
		||||
	local function dropdown_op(x, y, name, val)
 | 
			
		||||
		local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
 | 
			
		||||
				.. "0.75,0.5;" .. name .. ";" -- the height seems to be ignored?
 | 
			
		||||
@@ -180,26 +190,20 @@ plg.to_formspec_string = function(is)
 | 
			
		||||
		return s .. "]"
 | 
			
		||||
	end
 | 
			
		||||
	local function dropdown_action(x, y, name, val)
 | 
			
		||||
		local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
 | 
			
		||||
				.. "1.125,0.5;" .. name .. ";" -- the height seems to be ignored?
 | 
			
		||||
		s = s .. " , AND,  OR, NOT, XOR,NAND,   =,XNOR;"
 | 
			
		||||
		if val == nil then
 | 
			
		||||
			return s .. "0]" -- actually selects no field at all
 | 
			
		||||
		local selected = 0
 | 
			
		||||
		local titles = { " " }
 | 
			
		||||
		for i, data in ipairs(lcore.get_operations()) do
 | 
			
		||||
			titles[i + 1] = data.fs_name
 | 
			
		||||
			if val == data.gate then
 | 
			
		||||
				selected = i + 1
 | 
			
		||||
			end
 | 
			
		||||
		local mapping = {
 | 
			
		||||
			["and"] = 1,
 | 
			
		||||
			["or"] = 2,
 | 
			
		||||
			["not"] = 3,
 | 
			
		||||
			["xor"] = 4,
 | 
			
		||||
			["nand"] = 5,
 | 
			
		||||
			["buf"] = 6,
 | 
			
		||||
			["xnor"] = 7,
 | 
			
		||||
		}
 | 
			
		||||
		return s .. tostring(1 + mapping[val]) .. "]"
 | 
			
		||||
		end
 | 
			
		||||
		return ("dropdown[%f,%f;1.125,0.5;%s;%s;%i]"):format(
 | 
			
		||||
			x, y, name, table.concat(titles, ","), selected)
 | 
			
		||||
	end
 | 
			
		||||
	local s = "size[9,9]"..
 | 
			
		||||
		"label[3.4,-0.15;FPGA gate configuration]"..
 | 
			
		||||
		"button_exit[7,7.5;2,2.5;program;Program]"..
 | 
			
		||||
		"button[7,7.5;2,2.5;program;Program]"..
 | 
			
		||||
		"box[4.2,0.5;0.03,7;#ffffff]"..
 | 
			
		||||
		"label[0.25,0.25;op. 1]"..
 | 
			
		||||
		"label[1.0,0.25;gate type]"..
 | 
			
		||||
@@ -225,6 +229,12 @@ plg.to_formspec_string = function(is)
 | 
			
		||||
			y = 1 - 0.25
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	if err then
 | 
			
		||||
		local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg))
 | 
			
		||||
		s = s .. plg.red_box_around(err.i) ..
 | 
			
		||||
			"label[0.25,8.25;The gate configuration is erroneous in the marked area:]"..
 | 
			
		||||
			"label[0.25,8.5;" .. fmsg .. "]"
 | 
			
		||||
	end
 | 
			
		||||
	return s
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@@ -239,20 +249,11 @@ plg.from_formspec_fields = function(fields)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	local function read_action(s)
 | 
			
		||||
		if s == nil or s == " " then
 | 
			
		||||
			return nil
 | 
			
		||||
		for i, data in ipairs(lcore.get_operations()) do
 | 
			
		||||
			if data.fs_name == s then
 | 
			
		||||
				return data.gate
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
		local mapping = {
 | 
			
		||||
			["AND"] = "and",
 | 
			
		||||
			["OR"] = "or",
 | 
			
		||||
			["NOT"] = "not",
 | 
			
		||||
			["XOR"] = "xor",
 | 
			
		||||
			["NAND"] = "nand",
 | 
			
		||||
			["="] = "buf",
 | 
			
		||||
			["XNOR"] = "xnor",
 | 
			
		||||
		}
 | 
			
		||||
		s = s:gsub("^%s*", "") -- remove leading spaces
 | 
			
		||||
		return mapping[s]
 | 
			
		||||
	end
 | 
			
		||||
	local is = {}
 | 
			
		||||
	for i = 1, 14 do
 | 
			
		||||
@@ -266,12 +267,11 @@ plg.from_formspec_fields = function(fields)
 | 
			
		||||
	return is
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
plg.update_formspec = function(pos, is)
 | 
			
		||||
plg.update_meta = function(pos, is)
 | 
			
		||||
	if type(is) == "string" then -- serialized string
 | 
			
		||||
		is = lcore.deserialize(is)
 | 
			
		||||
	end
 | 
			
		||||
	local meta = minetest.get_meta(pos)
 | 
			
		||||
	local form = plg.to_formspec_string(is)
 | 
			
		||||
 | 
			
		||||
	local err = lcore.validate(is)
 | 
			
		||||
	if err == nil then
 | 
			
		||||
@@ -280,17 +280,20 @@ plg.update_formspec = function(pos, is)
 | 
			
		||||
	else
 | 
			
		||||
		meta:set_int("valid", 0)
 | 
			
		||||
		meta:set_string("infotext", "FPGA")
 | 
			
		||||
		local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg))
 | 
			
		||||
		form = form .. plg.red_box_around(err.i) ..
 | 
			
		||||
			"label[0.25,8.25;The gate configuration is erroneous in the marked area:]"..
 | 
			
		||||
			"label[0.25,8.5;" .. fmsg .. "]"
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	meta:set_string("formspec", form)
 | 
			
		||||
 | 
			
		||||
	-- reset ports and run programmed logic
 | 
			
		||||
	plg.setports(pos, false, false, false, false)
 | 
			
		||||
	plg.update(pos)
 | 
			
		||||
 | 
			
		||||
	-- Refresh open formspecs
 | 
			
		||||
	local form = plg.to_formspec_string(is, err)
 | 
			
		||||
	for name, open_pos in pairs(plg.open_formspecs) do
 | 
			
		||||
		if vector.equals(pos, open_pos) then
 | 
			
		||||
			minetest.show_formspec(name, "mesecons:fpga", form)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	return err
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
plg.red_box_around = function(i)
 | 
			
		||||
@@ -409,6 +412,38 @@ plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
 | 
			
		||||
	local player_name = player:get_player_name()
 | 
			
		||||
 | 
			
		||||
	if formname ~= "mesecons:fpga" or fields.quit then
 | 
			
		||||
		plg.open_formspecs[player_name] = nil -- potential garbage
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	if not fields.program then
 | 
			
		||||
		return -- we only care when the user clicks "Program"
 | 
			
		||||
	end
 | 
			
		||||
	local pos = plg.open_formspecs[player_name]
 | 
			
		||||
	if minetest.is_protected(pos, player_name) then
 | 
			
		||||
		minetest.record_protection_violation(pos, player_name)
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local meta = minetest.get_meta(pos)
 | 
			
		||||
	local is = plg.from_formspec_fields(fields)
 | 
			
		||||
 | 
			
		||||
	meta:set_string("instr", lcore.serialize(is))
 | 
			
		||||
	local err = plg.update_meta(pos, is)
 | 
			
		||||
 | 
			
		||||
	if not err then
 | 
			
		||||
		plg.open_formspecs[player_name] = nil
 | 
			
		||||
		-- Close on success
 | 
			
		||||
		minetest.close_formspec(player_name, "mesecons:fpga")
 | 
			
		||||
	end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
minetest.register_on_leaveplayer(function(player)
 | 
			
		||||
	plg.open_formspecs[player:get_player_name()] = nil
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
minetest.register_craft({
 | 
			
		||||
	output = "mesecons_fpga:fpga0000 2",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,27 @@
 | 
			
		||||
 | 
			
		||||
local lg = {}
 | 
			
		||||
 | 
			
		||||
local operations = {
 | 
			
		||||
	-- table index: Index in the formspec dropdown
 | 
			
		||||
	-- gate:    Internal name
 | 
			
		||||
	-- short:   Serialized form, single character
 | 
			
		||||
	-- fs_name: Display name, padded to 4 characters
 | 
			
		||||
	-- func:    Function that applies the operation
 | 
			
		||||
	-- unary:   Whether this gate only has one input
 | 
			
		||||
	{ gate = "and",  short = "&", fs_name = " AND", func = function(a, b) return a and b end },
 | 
			
		||||
	{ gate = "or",   short = "|", fs_name = "  OR", func = function(a, b) return a or b end },
 | 
			
		||||
	{ gate = "not",  short = "~", fs_name = " NOT", func = function(a, b) return not b end, unary = true },
 | 
			
		||||
	{ gate = "xor",  short = "^", fs_name = " XOR", func = function(a, b) return a ~= b end },
 | 
			
		||||
	{ gate = "nand", short = "?", fs_name = "NAND", func = function(a, b) return not (a and b) end },
 | 
			
		||||
	{ gate = "buf",  short = "_", fs_name = "   =", func = function(a, b) return b end, unary = true },
 | 
			
		||||
	{ gate = "xnor", short = "=", fs_name = "XNOR", func = function(a, b) return a == b end },
 | 
			
		||||
	{ gate = "nor",  short = "!", fs_name = " NOR", func = function(a, b) return not (a or b) end },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lg.get_operations = function()
 | 
			
		||||
	return operations
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- (de)serialize
 | 
			
		||||
lg.serialize = function(t)
 | 
			
		||||
	local function _op(t)
 | 
			
		||||
@@ -11,20 +33,14 @@ lg.serialize = function(t)
 | 
			
		||||
			return tostring(t.n)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	local function _action(s)
 | 
			
		||||
		if s == nil then
 | 
			
		||||
			return " "
 | 
			
		||||
	-- Serialize actions (gates) from eg. "and" to "&"
 | 
			
		||||
	local function _action(action)
 | 
			
		||||
		for i, data in ipairs(operations) do
 | 
			
		||||
			if data.gate == action then
 | 
			
		||||
				return data.short
 | 
			
		||||
			end
 | 
			
		||||
		local mapping = {
 | 
			
		||||
			["and"] = "&",
 | 
			
		||||
			["or"] = "|",
 | 
			
		||||
			["not"] = "~",
 | 
			
		||||
			["xor"] = "^",
 | 
			
		||||
			["nand"] = "?", --dunno
 | 
			
		||||
			["buf"] = "_",
 | 
			
		||||
			["xnor"] = "=",
 | 
			
		||||
		}
 | 
			
		||||
		return mapping[s]
 | 
			
		||||
		end
 | 
			
		||||
		return " "
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local s = ""
 | 
			
		||||
@@ -48,18 +64,14 @@ lg.deserialize = function(s)
 | 
			
		||||
			return {type = "reg", n = tonumber(c)}
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	local function _action(c)
 | 
			
		||||
		local mapping = {
 | 
			
		||||
			["&"] = "and",
 | 
			
		||||
			["|"] = "or",
 | 
			
		||||
			["~"] = "not",
 | 
			
		||||
			["^"] = "xor",
 | 
			
		||||
			["?"] = "nand",
 | 
			
		||||
			["_"] = "buf",
 | 
			
		||||
			["="] = "xnor",
 | 
			
		||||
			[" "] = nil,
 | 
			
		||||
		}
 | 
			
		||||
		return mapping[c]
 | 
			
		||||
	-- Deserialize actions (gates) from eg. "&" to "and"
 | 
			
		||||
	local function _action(action)
 | 
			
		||||
		for i, data in ipairs(operations) do
 | 
			
		||||
			if data.short == action then
 | 
			
		||||
				return data.gate
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
		-- nil
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local ret = {}
 | 
			
		||||
@@ -109,16 +121,25 @@ lg.validate_single = function(t, i)
 | 
			
		||||
		return false
 | 
			
		||||
	end
 | 
			
		||||
	local elem = t[i]
 | 
			
		||||
 | 
			
		||||
	local gate_data
 | 
			
		||||
	for j, data in ipairs(operations) do
 | 
			
		||||
		if data.gate == elem.action then
 | 
			
		||||
			gate_data = data
 | 
			
		||||
			break
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- check for completeness
 | 
			
		||||
	if elem.action == nil then
 | 
			
		||||
		return {i = i, msg = "Gate type required"}
 | 
			
		||||
	elseif elem.action == "not" or elem.action == "buf" then
 | 
			
		||||
	if not gate_data then
 | 
			
		||||
		return {i = i, msg = "Gate type is required"}
 | 
			
		||||
	elseif gate_data.unary then
 | 
			
		||||
		if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil then
 | 
			
		||||
			return {i = i, msg = "Second operand (only) and destination required"}
 | 
			
		||||
			return {i = i, msg = "Second operand (only) and destination are required"}
 | 
			
		||||
		end
 | 
			
		||||
	else
 | 
			
		||||
		if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then
 | 
			
		||||
			return {i = i, msg = "Operands and destination required"}
 | 
			
		||||
			return {i = i, msg = "Operands and destination are required"}
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	-- check whether operands/destination are identical
 | 
			
		||||
@@ -159,22 +180,13 @@ end
 | 
			
		||||
-- interpreter
 | 
			
		||||
lg.interpret = function(t, a, b, c, d)
 | 
			
		||||
	local function _action(s, v1, v2)
 | 
			
		||||
		if s == "and" then
 | 
			
		||||
			return v1 and v2
 | 
			
		||||
		elseif s == "or" then
 | 
			
		||||
			return v1 or v2
 | 
			
		||||
		elseif s == "not" then
 | 
			
		||||
			return not v2
 | 
			
		||||
		elseif s == "xor" then
 | 
			
		||||
			return v1 ~= v2
 | 
			
		||||
		elseif s == "nand" then
 | 
			
		||||
			return not (v1 and v2)
 | 
			
		||||
		elseif s == "buf" then
 | 
			
		||||
			return v2
 | 
			
		||||
		else -- s == "xnor"
 | 
			
		||||
			return v1 == v2
 | 
			
		||||
		for i, data in ipairs(operations) do
 | 
			
		||||
			if data.gate == s then
 | 
			
		||||
				return data.func(v1, v2)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
		return false -- unknown gate
 | 
			
		||||
	end
 | 
			
		||||
	local function _op(t, regs, io_in)
 | 
			
		||||
		if t.type == "reg" then
 | 
			
		||||
			return regs[t.n]
 | 
			
		||||
 
 | 
			
		||||
@@ -34,17 +34,22 @@ minetest.register_tool("mesecons_fpga:programmer", {
 | 
			
		||||
		if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then
 | 
			
		||||
			return itemstack
 | 
			
		||||
		end
 | 
			
		||||
		local player_name = user:get_player_name()
 | 
			
		||||
		if minetest.is_protected(pos, player_name) then
 | 
			
		||||
			minetest.record_protection_violation(pos, player_name)
 | 
			
		||||
			return itemstack
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local imeta = itemstack:get_metadata()
 | 
			
		||||
		if imeta == "" then
 | 
			
		||||
			minetest.chat_send_player(user:get_player_name(), "Use shift+right-click to copy a gate configuration first.")
 | 
			
		||||
			minetest.chat_send_player(player_name, "Use shift+right-click to copy a gate configuration first.")
 | 
			
		||||
			return itemstack
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local meta = minetest.get_meta(pos)
 | 
			
		||||
		meta:set_string("instr", imeta)
 | 
			
		||||
		plg.update_formspec(pos, imeta)
 | 
			
		||||
		minetest.chat_send_player(user:get_player_name(), "Gate configuration was successfully written to FPGA!")
 | 
			
		||||
		plg.update_meta(pos, imeta)
 | 
			
		||||
		minetest.chat_send_player(player_name, "Gate configuration was successfully written to FPGA!")
 | 
			
		||||
 | 
			
		||||
		return itemstack
 | 
			
		||||
	end
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,14 @@
 | 
			
		||||
local selection_box = {
 | 
			
		||||
	type = "fixed",
 | 
			
		||||
	fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local nodebox = {
 | 
			
		||||
	type = "fixed",
 | 
			
		||||
	fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }},
 | 
			
		||||
	fixed = {
 | 
			
		||||
		{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab
 | 
			
		||||
		{ -6/16, -7/16, -6/16, 6/16, -6/16, 6/16 }
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local function gate_rotate_rules(node, rules)
 | 
			
		||||
@@ -68,7 +76,7 @@ local function register_gate(name, inputnumber, assess, recipe, description)
 | 
			
		||||
		is_ground_content = false,
 | 
			
		||||
		drawtype = "nodebox",
 | 
			
		||||
		drop = basename.."_off",
 | 
			
		||||
		selection_box = nodebox,
 | 
			
		||||
		selection_box = selection_box,
 | 
			
		||||
		node_box = nodebox,
 | 
			
		||||
		walkable = true,
 | 
			
		||||
		sounds = default.node_sound_stone_defaults(),
 | 
			
		||||
@@ -78,8 +86,16 @@ local function register_gate(name, inputnumber, assess, recipe, description)
 | 
			
		||||
		inputnumber = inputnumber,
 | 
			
		||||
		after_dig_node = mesecon.do_cooldown,
 | 
			
		||||
	},{
 | 
			
		||||
		tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^"..
 | 
			
		||||
			"jeija_gate_"..name..".png"},
 | 
			
		||||
		tiles = {
 | 
			
		||||
			"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^"..
 | 
			
		||||
			"jeija_gate_output_off.png^".."jeija_gate_"..name..".png",
 | 
			
		||||
			"jeija_microcontroller_bottom.png^".."jeija_gate_output_off.png^"..
 | 
			
		||||
			"[transformFY",
 | 
			
		||||
			"jeija_gate_side.png^".."jeija_gate_side_output_off.png",
 | 
			
		||||
			"jeija_gate_side.png",
 | 
			
		||||
			"jeija_gate_side.png",
 | 
			
		||||
			"jeija_gate_side.png"
 | 
			
		||||
		},
 | 
			
		||||
		groups = {dig_immediate = 2, overheat = 1},
 | 
			
		||||
		mesecons = { receptor = {
 | 
			
		||||
			state = "off",
 | 
			
		||||
@@ -89,8 +105,16 @@ local function register_gate(name, inputnumber, assess, recipe, description)
 | 
			
		||||
			action_change = update_gate
 | 
			
		||||
		}}
 | 
			
		||||
	},{
 | 
			
		||||
		tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_on.png^"..
 | 
			
		||||
			"jeija_gate_"..name..".png"},
 | 
			
		||||
		tiles = {
 | 
			
		||||
			"jeija_microcontroller_bottom.png^".."jeija_gate_on.png^"..
 | 
			
		||||
			"jeija_gate_output_on.png^".."jeija_gate_"..name..".png",
 | 
			
		||||
			"jeija_microcontroller_bottom.png^".."jeija_gate_output_on.png^"..
 | 
			
		||||
			"[transformFY",
 | 
			
		||||
			"jeija_gate_side.png^".."jeija_gate_side_output_on.png",
 | 
			
		||||
			"jeija_gate_side.png",
 | 
			
		||||
			"jeija_gate_side.png",
 | 
			
		||||
			"jeija_gate_side.png"
 | 
			
		||||
		},
 | 
			
		||||
		groups = {dig_immediate = 2, not_in_creative_inventory = 1, overheat = 1},
 | 
			
		||||
		mesecons = { receptor = {
 | 
			
		||||
			state = "on",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_output_off.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_output_off.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 98 B  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_output_on.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_output_on.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 99 B  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_side.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_side.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 136 B  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_side_output_off.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_side_output_off.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 109 B  | 
							
								
								
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_side_output_on.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mesecons_gates/textures/jeija_gate_side_output_on.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 110 B  | 
@@ -163,7 +163,7 @@ local function add_pos(positions, pos)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function are_protected(positions, player_name)
 | 
			
		||||
	local mode = mesecon.setting("mvps_protection_mode", "normal")
 | 
			
		||||
	local mode = mesecon.setting("mvps_protection_mode", "compat")
 | 
			
		||||
	if mode == "ignore" then
 | 
			
		||||
		return false
 | 
			
		||||
	end
 | 
			
		||||
@@ -285,7 +285,7 @@ function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor)
 | 
			
		||||
	end
 | 
			
		||||
	movefactor = movefactor or 1
 | 
			
		||||
	dir = vector.multiply(dir, movefactor)
 | 
			
		||||
	for id, obj in pairs(minetest.object_refs) do
 | 
			
		||||
	for id, obj in pairs(minetest.get_objects_inside_radius(pos, #nodestack + 1)) do
 | 
			
		||||
		local obj_pos = obj:get_pos()
 | 
			
		||||
		local cbox = obj:get_properties().collisionbox
 | 
			
		||||
		local min_pos = vector.add(obj_pos, vector.new(cbox[1], cbox[2], cbox[3]))
 | 
			
		||||
 
 | 
			
		||||
@@ -74,8 +74,8 @@ minetest.register_abm(
 | 
			
		||||
	{nodenames = {"mesecons_solarpanel:solar_panel_off"},
 | 
			
		||||
	interval = 1,
 | 
			
		||||
	chance = 1,
 | 
			
		||||
	action = function(pos, node, active_object_count, active_object_count_wider)
 | 
			
		||||
		local light = minetest.get_node_light(pos, nil)
 | 
			
		||||
	action = function(pos, node)
 | 
			
		||||
		local light = minetest.get_node_light(pos)
 | 
			
		||||
 | 
			
		||||
		if light >= 12 then
 | 
			
		||||
			node.name = "mesecons_solarpanel:solar_panel_on"
 | 
			
		||||
@@ -89,8 +89,8 @@ minetest.register_abm(
 | 
			
		||||
	{nodenames = {"mesecons_solarpanel:solar_panel_on"},
 | 
			
		||||
	interval = 1,
 | 
			
		||||
	chance = 1,
 | 
			
		||||
	action = function(pos, node, active_object_count, active_object_count_wider)
 | 
			
		||||
		local light = minetest.get_node_light(pos, nil)
 | 
			
		||||
	action = function(pos, node)
 | 
			
		||||
		local light = minetest.get_node_light(pos)
 | 
			
		||||
 | 
			
		||||
		if light < 12 then
 | 
			
		||||
			node.name = "mesecons_solarpanel:solar_panel_off"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user