mirror of
				https://github.com/minetest-mods/mesecons.git
				synced 2025-10-31 03:15:35 +01:00 
			
		
		
		
	Compare commits
	
		
			12 Commits
		
	
	
		
			detector_b
			...
			4ecc694518
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 4ecc694518 | |||
| 3dd0eb7e4f | |||
| e4d7c07962 | |||
| 69a4b6b332 | |||
| e38e4fe0c5 | |||
| 5ad1e6bc4d | |||
| b91fe92d13 | |||
| 6a87290ead | |||
| 1963bfcc0d | |||
| 6936c8c2e4 | |||
| 2fc1682c04 | |||
| 9b835053c2 | 
							
								
								
									
										26
									
								
								.github/workflows/check-release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								.github/workflows/check-release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -13,29 +13,3 @@ jobs: | ||||
|       run: luarocks install --local luacheck | ||||
|     - name: luacheck run | ||||
|       run: $HOME/.luarocks/bin/luacheck ./ | ||||
|  | ||||
|   test: | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@main | ||||
|     - name: apt | ||||
|       run: sudo apt-get install -y luarocks | ||||
|     - name: busted install | ||||
|       run: luarocks install --local busted | ||||
|     - name: luacov install | ||||
|       run: luarocks install --local luacov | ||||
|     - name: mineunit install | ||||
|       run: luarocks install --server=https://luarocks.org/dev --local mineunit | ||||
|     - name: run mesecons tests | ||||
|       working-directory: ./mesecons/ | ||||
|       run: $HOME/.luarocks/bin/mineunit -q | ||||
|     - name: run mesecons_mvps tests | ||||
|       working-directory: ./mesecons_mvps/ | ||||
|       run: $HOME/.luarocks/bin/mineunit -q | ||||
|     - name: run mesecons_fpga tests | ||||
|       working-directory: ./mesecons_fpga/ | ||||
|       run: $HOME/.luarocks/bin/mineunit -q | ||||
|     - name: run mesecons_luacontroller tests | ||||
|       working-directory: ./mesecons_luacontroller/ | ||||
|       run: $HOME/.luarocks/bin/mineunit -q | ||||
|   | ||||
							
								
								
									
										23
									
								
								.luacheckrc
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								.luacheckrc
									
									
									
									
									
								
							| @@ -34,26 +34,3 @@ globals = {"mesecon"} | ||||
| files["mesecons/actionqueue.lua"] = { | ||||
| 	globals = {"minetest.registered_globalsteps"}, | ||||
| } | ||||
|  | ||||
| -- Test-specific stuff follows. | ||||
|  | ||||
| local test_conf = { | ||||
| 	read_globals = { | ||||
| 		"assert", | ||||
| 		"fixture", | ||||
| 		"mineunit", | ||||
| 		"Player", | ||||
| 		"sourcefile", | ||||
| 		"world", | ||||
| 	}, | ||||
| } | ||||
| files["*/spec/*.lua"] = test_conf | ||||
| files[".test_fixtures/*.lua"] = test_conf | ||||
|  | ||||
| files[".test_fixtures/screwdriver.lua"] = { | ||||
| 	globals = {"screwdriver"}, | ||||
| } | ||||
|  | ||||
| files[".test_fixtures/mesecons_fpga.lua"] = { | ||||
| 	globals = {"minetest.register_on_player_receive_fields"}, | ||||
| } | ||||
|   | ||||
| @@ -1,156 +0,0 @@ | ||||
| mineunit("core") | ||||
| mineunit("server") | ||||
| mineunit("voxelmanip") | ||||
|  | ||||
| mineunit:set_current_modname("mesecons") | ||||
| mineunit:set_modpath("mesecons", "../mesecons") | ||||
| sourcefile("../mesecons/init") | ||||
|  | ||||
| -- Utility node: this conductor is used to test the connectivity and state of adjacent wires. | ||||
| do | ||||
| 	local off_spec = {conductor = { | ||||
| 		state = mesecon.state.off, | ||||
| 		rules = mesecon.rules.alldirs, | ||||
| 		onstate = "mesecons:test_conductor_on", | ||||
| 	}} | ||||
| 	local on_spec = {conductor = { | ||||
| 		state = mesecon.state.on, | ||||
| 		rules = mesecon.rules.alldirs, | ||||
| 		offstate = "mesecons:test_conductor_off", | ||||
| 	}} | ||||
| 	mesecon.register_node("mesecons:test_conductor", { | ||||
| 		description = "Test Conductor", | ||||
| 	}, {mesecons = off_spec}, {mesecons = on_spec}) | ||||
| end | ||||
|  | ||||
| -- Utility node: this receptor is used to test power sources. | ||||
| do | ||||
| 	local off_spec = {receptor = { | ||||
| 		state = mesecon.state.off, | ||||
| 		rules = mesecon.rules.alldirs, | ||||
| 	}} | ||||
| 	local on_spec = {receptor = { | ||||
| 		state = mesecon.state.on, | ||||
| 		rules = mesecon.rules.alldirs, | ||||
| 	}} | ||||
| 	mesecon.register_node("mesecons:test_receptor", { | ||||
| 		description = "Test Receptor", | ||||
| 	}, {mesecons = off_spec}, {mesecons = on_spec}) | ||||
| end | ||||
|  | ||||
| -- Utility node: this effector is used to test circuit outputs. | ||||
| do | ||||
| 	-- This is a list of actions in the form {<kind>, <pos>}, | ||||
| 	-- where <kind> is "on", "off", or "overheat". | ||||
| 	mesecon._test_effector_events = {} | ||||
| 	local function action_on(pos, node) | ||||
| 		table.insert(mesecon._test_effector_events, {"on", pos}) | ||||
| 		node.param2 = node.param2 % 64 + 128 -- Turn on bit 7 | ||||
| 		minetest.swap_node(pos, node) | ||||
| 	end | ||||
| 	local function action_off(pos, node) | ||||
| 		table.insert(mesecon._test_effector_events, {"off", pos}) | ||||
| 		node.param2 = node.param2 % 64 -- Turn off bit 7 | ||||
| 		minetest.swap_node(pos, node) | ||||
| 	end | ||||
| 	local function action_change(pos, node, rule_name, new_state) | ||||
| 		if mesecon.do_overheat(pos) then | ||||
| 			table.insert(mesecon._test_effector_events, {"overheat", pos}) | ||||
| 			minetest.remove_node(pos) | ||||
| 			return | ||||
| 		end | ||||
| 		-- Set the value of a bit in param2 according to the rule name and new state. | ||||
| 		local bit = tonumber(rule_name.name, 2) | ||||
| 		local bits_above = node.param2 - node.param2 % (bit * 2) | ||||
| 		local bits_below = node.param2 % bit | ||||
| 		local bits_flipped = new_state == mesecon.state.on and bit or 0 | ||||
| 		node.param2 = bits_above + bits_flipped + bits_below | ||||
| 		minetest.swap_node(pos, node) | ||||
| 	end | ||||
| 	minetest.register_node("mesecons:test_effector", { | ||||
| 		description = "Test Effector", | ||||
| 		mesecons = {effector = { | ||||
| 			action_on = action_on, | ||||
| 			action_off = action_off, | ||||
| 			action_change = action_change, | ||||
| 			rules = { | ||||
| 				{x =  1, y =  0, z =  0, name = "000001"}, | ||||
| 				{x = -1, y =  0, z =  0, name = "000010"}, | ||||
| 				{x =  0, y =  1, z =  0, name = "000100"}, | ||||
| 				{x =  0, y = -1, z =  0, name = "001000"}, | ||||
| 				{x =  0, y =  0, z =  1, name = "010000"}, | ||||
| 				{x =  0, y =  0, z = -1, name = "100000"}, | ||||
| 			} | ||||
| 		}}, | ||||
| 	}) | ||||
| end | ||||
|  | ||||
| -- Utility node: this conductor is used to test rotation. | ||||
| do | ||||
| 	local get_rules = mesecon.horiz_rules_getter({{x = 1, y = 0, z = 0}, {x = -1, y = 0, z = 0}}) | ||||
| 	local off_spec = {conductor = { | ||||
| 		state = mesecon.state.off, | ||||
| 		rules = get_rules, | ||||
| 		onstate = "mesecons:test_conductor_rot_on", | ||||
| 	}} | ||||
| 	local on_spec = {conductor = { | ||||
| 		state = mesecon.state.on, | ||||
| 		rules = get_rules, | ||||
| 		offstate = "mesecons:test_conductor_rot_off", | ||||
| 	}} | ||||
| 	mesecon.register_node("mesecons:test_conductor_rot", { | ||||
| 		description = "Rotatable Test Conductor", | ||||
| 		on_rotate = mesecon.on_rotate_horiz, | ||||
| 	}, {mesecons = off_spec}, {mesecons = on_spec}) | ||||
| end | ||||
|  | ||||
| -- Utility node: this is used to test multiple conductors within a single node. | ||||
| do | ||||
| 	local mesecons_spec = {conductor = { | ||||
| 		rules = { | ||||
| 			{{x = 1, y = 0, z = 0}, {x = 0, y = -1, z = 0}}, | ||||
| 			{{x = 0, y = 1, z = 0}, {x = 0, y = 0, z = -1}}, | ||||
| 			{{x = 0, y = 0, z = 1}, {x = -1, y = 0, z = 0}}, | ||||
| 		}, | ||||
| 		states = { | ||||
| 			"mesecons:test_multiconductor_off", "mesecons:test_multiconductor_001", | ||||
| 			"mesecons:test_multiconductor_010", "mesecons:test_multiconductor_011", | ||||
| 			"mesecons:test_multiconductor_100", "mesecons:test_multiconductor_101", | ||||
| 			"mesecons:test_multiconductor_110", "mesecons:test_multiconductor_on", | ||||
| 		}, | ||||
| 	}} | ||||
| 	for _, state in ipairs(mesecons_spec.conductor.states) do | ||||
| 		minetest.register_node(state, { | ||||
| 			description = "Test Multiconductor", | ||||
| 			mesecons = mesecons_spec, | ||||
| 		}) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| mesecon._test_autoconnects = {} | ||||
| mesecon.register_autoconnect_hook("test", function(pos, node) | ||||
| 	table.insert(mesecon._test_autoconnects, {pos, node}) | ||||
| end) | ||||
|  | ||||
| function mesecon._test_dig(pos) | ||||
| 	local node = minetest.get_node(pos) | ||||
| 	minetest.remove_node(pos) | ||||
| 	mesecon.on_dignode(pos, node) | ||||
| end | ||||
|  | ||||
| function mesecon._test_place(pos, node) | ||||
| 	world.set_node(pos, node) | ||||
| 	mesecon.on_placenode(pos, minetest.get_node(pos)) | ||||
| end | ||||
|  | ||||
| function mesecon._test_reset() | ||||
| 	-- First let circuits settle by simulating many globalsteps. | ||||
| 	for i = 1, 10 do | ||||
| 		mineunit:execute_globalstep(60) | ||||
| 	end | ||||
| 	mesecon.queue.actions = {} | ||||
| 	mesecon._test_effector_events = {} | ||||
| 	mesecon._test_autoconnects = {} | ||||
| end | ||||
|  | ||||
| mineunit:execute_globalstep(mesecon.setting("resumetime", 4) + 1) | ||||
| @@ -1,59 +0,0 @@ | ||||
| mineunit("player") | ||||
|  | ||||
| fixture("mesecons") | ||||
| fixture("mesecons_gamecompat") | ||||
|  | ||||
| local registered_on_player_receive_fields = {} | ||||
| local old_register_on_player_receive_fields = minetest.register_on_player_receive_fields | ||||
| function minetest.register_on_player_receive_fields(func) | ||||
| 	old_register_on_player_receive_fields(func) | ||||
| 	table.insert(registered_on_player_receive_fields, func) | ||||
| end | ||||
|  | ||||
| mineunit:set_current_modname("mesecons_fpga") | ||||
| mineunit:set_modpath("mesecons_fpga", "../mesecons_fpga") | ||||
| sourcefile("../mesecons_fpga/init") | ||||
|  | ||||
| local fpga_user = Player("mesecons_fpga_user") | ||||
|  | ||||
| function mesecon._test_program_fpga(pos, program) | ||||
| 	local node = minetest.get_node(pos) | ||||
| 	assert.equal("mesecons_fpga:fpga", node.name:sub(1, 18)) | ||||
|  | ||||
| 	local fields = {program = true} | ||||
| 	for i, instr in ipairs(program) do | ||||
| 		-- Translate the instruction into formspec fields. | ||||
| 		local op1, act, op2, dst | ||||
| 		if #instr == 3 then | ||||
| 			act, op2, dst = unpack(instr) | ||||
| 		else | ||||
| 			assert.equal(4, #instr) | ||||
| 			op1, act, op2, dst = unpack(instr) | ||||
| 		end | ||||
| 		fields[i .. "op1"] = op1 | ||||
| 		fields[i .. "act"] = (" "):rep(4 - #act) .. act | ||||
| 		fields[i .. "op2"] = op2 | ||||
| 		fields[i .. "dst"] = dst | ||||
| 	end | ||||
|  | ||||
| 	minetest.registered_nodes[node.name].on_rightclick(pos, node, fpga_user) | ||||
|  | ||||
| 	for _, func in ipairs(registered_on_player_receive_fields) do | ||||
| 		if func(fpga_user, "mesecons:fpga", fields) then | ||||
| 			break | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function mesecon._test_copy_fpga_program(pos) | ||||
| 	fpga_user:get_inventory():set_stack("main", 1, "mesecons_fpga:programmer") | ||||
| 	local pt = {type = "node", under = vector.new(pos), above = vector.offset(pos, 0, 1, 0)} | ||||
| 	fpga_user:do_place(pt) | ||||
| 	return fpga_user:get_wielded_item() | ||||
| end | ||||
|  | ||||
| function mesecon._test_paste_fpga_program(pos, tool) | ||||
| 	fpga_user:get_inventory():set_stack("main", 1, tool) | ||||
| 	local pt = {type = "node", under = vector.new(pos), above = vector.offset(pos, 0, 1, 0)} | ||||
| 	fpga_user:do_use(pt) | ||||
| end | ||||
| @@ -1,5 +0,0 @@ | ||||
| fixture("mesecons") | ||||
|  | ||||
| mineunit:set_current_modname("mesecons_gamecompat") | ||||
| mineunit:set_modpath("mesecons_gamecompat", "../mesecons_gamecompat") | ||||
| sourcefile("../mesecons_gamecompat/init") | ||||
| @@ -1,12 +0,0 @@ | ||||
| fixture("mesecons") | ||||
| fixture("mesecons_gamecompat") | ||||
|  | ||||
| mineunit:set_current_modname("mesecons_luacontroller") | ||||
| mineunit:set_modpath("mesecons_luacontroller", "../mesecons_luacontroller") | ||||
| sourcefile("../mesecons_luacontroller/init") | ||||
|  | ||||
| function mesecon._test_program_luac(pos, code) | ||||
| 	local node = minetest.get_node(pos) | ||||
| 	assert.equal("mesecons_luacontroller:luacontroller", node.name:sub(1, 36)) | ||||
| 	return minetest.registered_nodes[node.name].mesecons.luacontroller.set_program(pos, code) | ||||
| end | ||||
| @@ -1,45 +0,0 @@ | ||||
| mineunit("protection") | ||||
|  | ||||
| fixture("mesecons") | ||||
|  | ||||
| mineunit:set_current_modname("mesecons_mvps") | ||||
| mineunit:set_modpath("mesecons_mvps", "../mesecons_mvps") | ||||
| sourcefile("../mesecons_mvps/init") | ||||
|  | ||||
| minetest.register_node("mesecons_mvps:test_stopper", { | ||||
| 	description = "Test Stopper", | ||||
| }) | ||||
| mesecon.register_mvps_stopper("mesecons_mvps:test_stopper") | ||||
|  | ||||
| minetest.register_node("mesecons_mvps:test_stopper_cond", { | ||||
| 	description = "Test Stopper (Conditional)", | ||||
| }) | ||||
| mesecon.register_mvps_stopper("mesecons_mvps:test_stopper_cond", function(node) | ||||
| 	return node.param2 == 0 | ||||
| end) | ||||
|  | ||||
| minetest.register_node("mesecons_mvps:test_sticky", { | ||||
| 	description = "Test Sticky", | ||||
| 	mvps_sticky = function(pos) | ||||
| 		local connected = {} | ||||
| 		for i, rule in ipairs(mesecon.rules.alldirs) do | ||||
| 			connected[i] = vector.add(pos, rule) | ||||
| 		end | ||||
| 		return connected | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
| mesecon._test_moves = {} | ||||
| minetest.register_node("mesecons_mvps:test_on_move", { | ||||
| 	description = "Test Moveable", | ||||
| 	mesecon = { | ||||
| 		on_mvps_move = function(pos, node, oldpos, meta) | ||||
| 			table.insert(mesecon._test_moves, {pos, node, oldpos, meta}) | ||||
| 		end | ||||
| 	}, | ||||
| }) | ||||
| local old_reset = mesecon._test_reset | ||||
| function mesecon._test_reset() | ||||
| 	mesecon._test_moves = {} | ||||
| 	old_reset() | ||||
| end | ||||
| @@ -1,6 +0,0 @@ | ||||
| mineunit:set_current_modname("screwdriver") | ||||
|  | ||||
| screwdriver = {} | ||||
|  | ||||
| screwdriver.ROTATE_FACE = 1 | ||||
| screwdriver.ROTATE_AXIS = 2 | ||||
| @@ -99,6 +99,7 @@ mesecon.queue:add_function("receptor_off", function (pos, rules) | ||||
| 		local rulenames = mesecon.rules_link_rule_all(pos, rule) | ||||
| 		for _, rulename in ipairs(rulenames) do | ||||
| 			mesecon.vm_begin() | ||||
| 			mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2) | ||||
|  | ||||
| 			-- Turnoff returns true if turnoff process was successful, no onstate receptor | ||||
| 			-- was found along the way. Commit changes that were made in voxelmanip. If turnoff | ||||
| @@ -117,6 +118,8 @@ function mesecon.receptor_off(pos, rules) | ||||
| end | ||||
|  | ||||
|  | ||||
| print("[OK] Mesecons") | ||||
|  | ||||
| -- Deprecated stuff | ||||
| -- To be removed in future releases | ||||
| dofile(minetest.get_modpath("mesecons").."/legacy.lua"); | ||||
|   | ||||
| @@ -51,18 +51,27 @@ mesecon.fifo_queue = dofile(minetest.get_modpath("mesecons").."/fifo_queue.lua") | ||||
|  | ||||
| -- General | ||||
| function mesecon.get_effector(nodename) | ||||
| 	local def = minetest.registered_nodes[nodename] | ||||
| 	return def and def.mesecons and def.mesecons.effector | ||||
| 	if  minetest.registered_nodes[nodename] | ||||
| 	and minetest.registered_nodes[nodename].mesecons | ||||
| 	and minetest.registered_nodes[nodename].mesecons.effector then | ||||
| 		return minetest.registered_nodes[nodename].mesecons.effector | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function mesecon.get_receptor(nodename) | ||||
| 	local def = minetest.registered_nodes[nodename] | ||||
| 	return def and def.mesecons and def.mesecons.receptor | ||||
| 	if  minetest.registered_nodes[nodename] | ||||
| 	and minetest.registered_nodes[nodename].mesecons | ||||
| 	and minetest.registered_nodes[nodename].mesecons.receptor then | ||||
| 		return minetest.registered_nodes[nodename].mesecons.receptor | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function mesecon.get_conductor(nodename) | ||||
| 	local def = minetest.registered_nodes[nodename] | ||||
| 	return def and def.mesecons and def.mesecons.conductor | ||||
| 	if  minetest.registered_nodes[nodename] | ||||
| 	and minetest.registered_nodes[nodename].mesecons | ||||
| 	and minetest.registered_nodes[nodename].mesecons.conductor then | ||||
| 		return minetest.registered_nodes[nodename].mesecons.conductor | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function mesecon.get_any_outputrules(node) | ||||
| @@ -533,12 +542,9 @@ function mesecon.turnoff(pos, link) | ||||
| 	end | ||||
|  | ||||
| 	for _, sig in ipairs(signals) do | ||||
| 		-- If sig.depth is 1, it has not yet been checked that the power source is actually off. | ||||
| 		if sig.depth > 1 or not mesecon.is_powered(sig.pos, sig.link) then | ||||
| 			mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth) | ||||
| 			if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then | ||||
| 				mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth) | ||||
| 			end | ||||
| 		mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth) | ||||
| 		if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then | ||||
| 			mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth) | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
|   | ||||
| @@ -1,3 +0,0 @@ | ||||
| # textdomain: mesecons | ||||
|  | ||||
| Mesecons=Mesecons | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons | ||||
|  | ||||
| ### oldwires.lua ### | ||||
| Mesecons=Mesekonduktilo | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons | ||||
|  | ||||
| ### oldwires.lua ### | ||||
| Mesecons= | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| minetest.register_node("mesecons:mesecon_off", { | ||||
| 	drawtype = "raillike", | ||||
| 	tiles = {"jeija_mesecon_off.png", "jeija_mesecon_curved_off.png", "jeija_mesecon_t_junction_off.png", "jeija_mesecon_crossing_off.png"}, | ||||
| @@ -13,7 +11,7 @@ minetest.register_node("mesecons:mesecon_off", { | ||||
| 		fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}, | ||||
| 	}, | ||||
| 	groups = {dig_immediate=3, mesecon=1, mesecon_conductor_craftable=1}, | ||||
| 	description= S("Mesecons"), | ||||
| 	description="Mesecons", | ||||
| 	mesecons = {conductor={ | ||||
| 		state = mesecon.state.off, | ||||
| 		onstate = "mesecons:mesecon_on" | ||||
|   | ||||
| @@ -64,8 +64,6 @@ local rules_buttonlike = { | ||||
| } | ||||
|  | ||||
| local function rules_from_dir(ruleset, dir) | ||||
| 	if not dir then return {} end | ||||
|  | ||||
| 	if dir.x ==  1 then return ruleset.xp end | ||||
| 	if dir.y ==  1 then return ruleset.yp end | ||||
| 	if dir.z ==  1 then return ruleset.zp end | ||||
|   | ||||
| @@ -1,62 +0,0 @@ | ||||
| require("mineunit") | ||||
|  | ||||
| fixture("mesecons") | ||||
|  | ||||
| describe("action queue", function() | ||||
| 	local layout = { | ||||
| 		{{x =  1, y = 0, z = 0}, "mesecons:test_receptor_off"}, | ||||
| 		{{x =  0, y = 0, z = 0}, "mesecons:test_conductor_off"}, | ||||
| 		{{x = -1, y = 0, z = 0}, "mesecons:test_conductor_off"}, | ||||
| 		{{x =  0, y = 1, z = 0}, "mesecons:test_effector"}, | ||||
| 		{{x = -1, y = 1, z = 0}, "mesecons:test_effector"}, | ||||
| 	} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		world.layout(layout) | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("executes in order", function() | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal(2, #mesecon._test_effector_events) | ||||
| 		assert.same({"on", layout[4][1]}, mesecon._test_effector_events[1]) | ||||
| 		assert.same({"on", layout[5][1]}, mesecon._test_effector_events[2]) | ||||
|  | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_off") | ||||
| 		mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal(4, #mesecon._test_effector_events) | ||||
| 		assert.same({"off", layout[4][1]}, mesecon._test_effector_events[3]) | ||||
| 		assert.same({"off", layout[5][1]}, mesecon._test_effector_events[4]) | ||||
| 	end) | ||||
|  | ||||
| 	it("discards outdated/overwritten node events", function() | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_off") | ||||
| 		mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal(0, #mesecon._test_effector_events) | ||||
| 	end) | ||||
|  | ||||
| 	it("delays actions", function() | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.queue:add_action(layout[1][1], "receptor_on", {mesecon.rules.alldirs}, 1, nil) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		mineunit:execute_globalstep(1) | ||||
| 		assert.equal(0, #mesecon._test_effector_events) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		assert.equal(0, #mesecon._test_effector_events) | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal(2, #mesecon._test_effector_events) | ||||
| 	end) | ||||
| end) | ||||
| @@ -1 +0,0 @@ | ||||
| fixture_paths = {"../.test_fixtures"} | ||||
| @@ -1,192 +0,0 @@ | ||||
| require("mineunit") | ||||
|  | ||||
| fixture("mesecons") | ||||
| fixture("screwdriver") | ||||
|  | ||||
| describe("placement/digging service", function() | ||||
| 	local layout = { | ||||
| 		{{x =  1, y = 0, z = 0}, "mesecons:test_receptor_on"}, | ||||
| 		{{x =  0, y = 0, z = 0}, "mesecons:test_conductor_on"}, | ||||
| 		{{x = -1, y = 0, z = 0}, "mesecons:test_conductor_on"}, | ||||
| 		{{x =  0, y = 1, z = 0}, "mesecons:test_effector"}, | ||||
| 		{{x = -2, y = 0, z = 0}, "mesecons:test_effector"}, | ||||
| 		{{x =  2, y = 0, z = 0}, "mesecons:test_effector"}, | ||||
| 	} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		world.layout(layout) | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("updates components when a receptor changes", function() | ||||
| 		-- Dig then replace a receptor and check that the connected effectors changed. | ||||
|  | ||||
| 		mesecon._test_dig(layout[1][1]) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(layout[2][1]).name) | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal(3, #mesecon._test_effector_events) | ||||
|  | ||||
| 		mesecon._test_place(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[2][1]).name) | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change action | ||||
| 		assert.equal(6, #mesecon._test_effector_events) | ||||
| 	end) | ||||
|  | ||||
| 	it("updates components when a conductor changes", function() | ||||
| 		-- Dig then replace a powered conductor and check that the connected effectors changed. | ||||
|  | ||||
| 		mesecon._test_dig(layout[2][1]) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name) | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal(2, #mesecon._test_effector_events) | ||||
|  | ||||
| 		mesecon._test_place(layout[2][1], "mesecons:test_conductor_off") | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[2][1]).name) | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal(4, #mesecon._test_effector_events) | ||||
| 	end) | ||||
|  | ||||
| 	it("updates effectors on placement", function() | ||||
| 		local pos = {x = 0, y = 0, z = 1} | ||||
| 		mesecon._test_place(pos, "mesecons:test_effector") | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal(tonumber("10100000", 2), world.get_node(pos).param2) | ||||
| 	end) | ||||
|  | ||||
| 	it("updates multiconductors on placement", function() | ||||
| 		local pos = {x = 0, y = 0, z = 1} | ||||
| 		mesecon._test_place(pos, "mesecons:test_multiconductor_off") | ||||
| 		assert.equal("mesecons:test_multiconductor_010", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("turns off conductors on placement", function() | ||||
| 		local pos = {x = 3, y = 0, z = 0} | ||||
| 		mesecon._test_place(pos, "mesecons:test_conductor_on") | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("turns off multiconductors on placement", function() | ||||
| 		local pos = {x = 3, y = 0, z = 0} | ||||
| 		mesecon._test_place(pos, "mesecons:test_multiconductor_on") | ||||
| 		assert.equal("mesecons:test_multiconductor_off", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("triggers autoconnect hooks", function() | ||||
| 		mesecon._test_dig(layout[2][1]) | ||||
| 		mineunit:execute_globalstep() -- Execute delayed hook | ||||
| 		assert.equal(1, #mesecon._test_autoconnects) | ||||
|  | ||||
| 		mesecon._test_place(layout[2][1], layout[2][2]) | ||||
| 		assert.equal(2, #mesecon._test_autoconnects) | ||||
| 	end) | ||||
| end) | ||||
|  | ||||
| describe("overheating service", function() | ||||
| 	local layout = { | ||||
| 		{{x = 0, y = 0, z = 0}, "mesecons:test_receptor_off"}, | ||||
| 		{{x = 1, y = 0, z = 0}, "mesecons:test_effector"}, | ||||
| 		{{x = 2, y = 0, z = 0}, "mesecons:test_receptor_on"}, | ||||
| 	} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		world.layout(layout) | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("tracks heat", function() | ||||
| 		mesecon.do_overheat(layout[2][1]) | ||||
| 		assert.equal(1, mesecon.get_heat(layout[2][1])) | ||||
| 		mesecon.do_cooldown(layout[2][1]) | ||||
| 		assert.equal(0, mesecon.get_heat(layout[2][1])) | ||||
| 	end) | ||||
|  | ||||
| 	it("cools over time", function() | ||||
| 		mesecon.do_overheat(layout[2][1]) | ||||
| 		assert.equal(1, mesecon.get_heat(layout[2][1])) | ||||
| 		mineunit:execute_globalstep(60) | ||||
| 		mineunit:execute_globalstep(60) | ||||
| 		mineunit:execute_globalstep(60) | ||||
| 		assert.equal(0, mesecon.get_heat(layout[2][1])) | ||||
| 	end) | ||||
|  | ||||
| 	it("tracks movement", function() | ||||
| 		local oldpos = layout[2][1] | ||||
| 		local pos = vector.offset(oldpos, 0, 1, 0) | ||||
| 		mesecon.do_overheat(oldpos) | ||||
| 		mesecon.move_hot_nodes({{pos = pos, oldpos = oldpos}}) | ||||
| 		assert.equal(0, mesecon.get_heat(oldpos)) | ||||
| 		assert.equal(1, mesecon.get_heat(pos)) | ||||
| 	end) | ||||
|  | ||||
| 	it("causes overheating", function() | ||||
| 		-- Switch the first receptor on and off until it overheats/breaks a receptor. | ||||
| 		repeat | ||||
| 			if mesecon.flipstate(layout[1][1], minetest.get_node(layout[1][1])) == "on" then | ||||
| 				mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) | ||||
| 			else | ||||
| 				mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs) | ||||
| 			end | ||||
| 			mineunit:execute_globalstep(0) -- Execute receptor_on/receptor_off/activate/deactivate/change actions | ||||
| 		until minetest.get_node(layout[2][1]).name ~= "mesecons:test_effector" | ||||
| 		assert.same({"overheat", layout[2][1]}, mesecon._test_effector_events[#mesecon._test_effector_events]) | ||||
| 		assert.equal(0, mesecon.get_heat(layout[2][1])) | ||||
| 	end) | ||||
| end) | ||||
|  | ||||
| describe("screwdriver service", function() | ||||
| 	local layout = { | ||||
| 		{{x =  0, y = 0, z =  0}, "mesecons:test_conductor_rot_on"}, | ||||
| 		{{x =  1, y = 0, z =  0}, "mesecons:test_receptor_on"}, | ||||
| 		{{x = -1, y = 0, z =  0}, "mesecons:test_conductor_on"}, | ||||
| 		{{x =  0, y = 0, z =  1}, "mesecons:test_receptor_on"}, | ||||
| 		{{x =  0, y = 0, z = -1}, "mesecons:test_conductor_off"}, | ||||
| 	} | ||||
|  | ||||
| 	local function rotate(new_param2) | ||||
| 		local pos = layout[1][1] | ||||
| 		local node = world.get_node(pos) | ||||
| 		local on_rotate = minetest.registered_nodes[node.name].on_rotate | ||||
| 		on_rotate(pos, node, nil, screwdriver.ROTATE_FACE, new_param2) | ||||
| 	end | ||||
|  | ||||
| 	before_each(function() | ||||
| 		world.layout(layout) | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("updates conductors", function() | ||||
| 		-- Rotate a conductor and see that the circuit state changes. | ||||
| 		rotate(1) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[5][1]).name) | ||||
| 		rotate(2) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(layout[5][1]).name) | ||||
| 		rotate(3) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[5][1]).name) | ||||
| 		rotate(0) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(layout[5][1]).name) | ||||
| 	end) | ||||
| end) | ||||
| @@ -1,147 +0,0 @@ | ||||
| require("mineunit") | ||||
|  | ||||
| fixture("mesecons") | ||||
|  | ||||
| describe("state", function() | ||||
| 	local layout = { | ||||
| 		{{x =  1, y =  0, z = 0}, "mesecons:test_receptor_off"}, | ||||
| 		{{x =  0, y =  1, z = 0}, "mesecons:test_receptor_off"}, | ||||
| 		{{x =  0, y =  0, z = 0}, "mesecons:test_conductor_off"}, | ||||
| 		{{x = -1, y =  0, z = 0}, "mesecons:test_effector"}, | ||||
| 		{{x =  2, y =  0, z = 0}, "mesecons:test_effector"}, | ||||
| 		{{x =  0, y = -1, z = 0}, "mesecons:test_effector"}, | ||||
| 	} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		world.layout(layout) | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("turns on", function() | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2) | ||||
| 		assert.equal(tonumber("10000010", 2), world.get_node(layout[5][1]).param2) | ||||
| 		assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2) | ||||
|  | ||||
| 		world.set_node(layout[2][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2) | ||||
| 		assert.equal(tonumber("10000010", 2), world.get_node(layout[5][1]).param2) | ||||
| 		assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2) | ||||
| 	end) | ||||
|  | ||||
| 	it("turns off", function() | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		world.set_node(layout[2][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on actions | ||||
|  | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_off") | ||||
| 		mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off and activate/change actions | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2) | ||||
| 		assert.equal(tonumber("00000000", 2), world.get_node(layout[5][1]).param2) | ||||
| 		assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2) | ||||
|  | ||||
| 		world.set_node(layout[2][1], "mesecons:test_receptor_off") | ||||
| 		mesecon.receptor_off(layout[2][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal(tonumber("00000000", 2), world.get_node(layout[4][1]).param2) | ||||
| 		assert.equal(tonumber("00000000", 2), world.get_node(layout[5][1]).param2) | ||||
| 		assert.equal(tonumber("00000000", 2), world.get_node(layout[6][1]).param2) | ||||
| 	end) | ||||
| end) | ||||
|  | ||||
| describe("rotation", function() | ||||
| 	local layout = { | ||||
| 		{{x =  0, y = 0, z =  0}, "mesecons:test_receptor_off"}, | ||||
| 		{{x =  1, y = 0, z =  0}, {name = "mesecons:test_conductor_rot_off", param2 = 0}}, | ||||
| 		{{x =  0, y = 0, z =  1}, {name = "mesecons:test_conductor_rot_off", param2 = 1}}, | ||||
| 		{{x = -1, y = 0, z =  0}, {name = "mesecons:test_conductor_rot_off", param2 = 2}}, | ||||
| 		{{x =  0, y = 0, z = -1}, {name = "mesecons:test_conductor_rot_off", param2 = 3}}, | ||||
| 	} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		for _, entry in ipairs(layout) do | ||||
| 			world.set_node(entry[1], entry[2]) | ||||
| 		end | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("works", function() | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[2][1]).name) | ||||
| 		assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[3][1]).name) | ||||
| 		assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[4][1]).name) | ||||
| 		assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[5][1]).name) | ||||
| 	end) | ||||
| end) | ||||
|  | ||||
| describe("multiconductor", function() | ||||
| 	local layout = { | ||||
| 		{{x =  1, y = 0, z =  0}, "mesecons:test_receptor_off"}, | ||||
| 		{{x =  0, y = 1, z =  0}, "mesecons:test_receptor_off"}, | ||||
| 		{{x =  0, y = 0, z =  1}, "mesecons:test_receptor_off"}, | ||||
| 		{{x =  0, y = 0, z =  0}, "mesecons:test_multiconductor_off"}, | ||||
| 	} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		world.layout(layout) | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		world.clear() | ||||
| 		mesecon._test_reset() | ||||
| 	end) | ||||
|  | ||||
| 	it("separates its subparts", function() | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		assert.equal("mesecons:test_multiconductor_001", world.get_node(layout[4][1]).name) | ||||
|  | ||||
| 		world.set_node(layout[2][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		assert.equal("mesecons:test_multiconductor_011", world.get_node(layout[4][1]).name) | ||||
|  | ||||
| 		world.set_node(layout[3][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[3][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		assert.equal("mesecons:test_multiconductor_on", world.get_node(layout[4][1]).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("loops through itself", function() | ||||
| 		-- Make a loop. | ||||
| 		world.set_node({x = 0, y = -1, z = 0}, "mesecons:test_conductor_off") | ||||
| 		world.set_node({x = -1, y = -1, z = 0}, "mesecons:test_conductor_off") | ||||
| 		world.set_node({x = -1, y = 0, z = 0}, "mesecons:test_conductor_off") | ||||
|  | ||||
| 		world.set_node(layout[1][1], "mesecons:test_receptor_on") | ||||
| 		mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		assert.equal("mesecons:test_multiconductor_101", world.get_node(layout[4][1]).name) | ||||
| 	end) | ||||
| end) | ||||
| @@ -1,7 +1,5 @@ | ||||
| -- The BLINKY_PLANT | ||||
|  | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local toggle_timer = function (pos) | ||||
| 	local timer = minetest.get_node_timer(pos) | ||||
| 	if timer:is_started() then | ||||
| @@ -22,7 +20,7 @@ local on_timer = function (pos) | ||||
| end | ||||
|  | ||||
| mesecon.register_node("mesecons_blinkyplant:blinky_plant", { | ||||
| 	description= S("Blinky Plant"), | ||||
| 	description="Blinky Plant", | ||||
| 	drawtype = "plantlike", | ||||
| 	inventory_image = "jeija_blinky_plant_off.png", | ||||
| 	paramtype = "light", | ||||
|   | ||||
| @@ -1,2 +0,0 @@ | ||||
| # textdomain: mesecons_blinkyplant | ||||
| Blinky Plant=Blinkpflanze | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_blinkyplant | ||||
|  | ||||
| ### init.lua ### | ||||
| Blinky Plant=Palpebruma Planto | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_blinkyplant | ||||
|  | ||||
| ### init.lua ### | ||||
| Blinky Plant= | ||||
| @@ -1,7 +1,6 @@ | ||||
| -- WALL BUTTON | ||||
| -- A button that when pressed emits power for 1 second | ||||
| -- and then turns off again | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| mesecon.button_turnoff = function (pos) | ||||
| 	local node = minetest.get_node(pos) | ||||
| @@ -46,7 +45,7 @@ minetest.register_node("mesecons_button:button_off", { | ||||
| 	} | ||||
| 	}, | ||||
| 	groups = {dig_immediate=2, mesecon_needs_receiver = 1}, | ||||
| 	description = S("Button"), | ||||
| 	description = "Button", | ||||
| 	on_rightclick = function (pos, node) | ||||
| 		minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2}) | ||||
| 		mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node)) | ||||
| @@ -93,7 +92,7 @@ minetest.register_node("mesecons_button:button_on", { | ||||
|     }, | ||||
| 	groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon_needs_receiver = 1}, | ||||
| 	drop = 'mesecons_button:button_off', | ||||
| 	description = S("Button"), | ||||
| 	description = "Button", | ||||
| 	sounds = mesecon.node_sound.stone, | ||||
| 	mesecons = {receptor = { | ||||
| 		state = mesecon.state.on, | ||||
|   | ||||
| @@ -1,2 +0,0 @@ | ||||
| # textdomain: mesecons_button | ||||
| Button=Taster | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_button | ||||
|  | ||||
| ### init.lua ### | ||||
| Button=Butono | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_button | ||||
|  | ||||
| ### init.lua ### | ||||
| Button= | ||||
| @@ -1,8 +1,6 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| minetest.register_chatcommand("say", { | ||||
| 	params = "<text>", | ||||
| 	description = S("Say <text> as the server"), | ||||
| 	description = "Say <text> as the server", | ||||
| 	privs = {server=true}, | ||||
| 	func = function(name, param) | ||||
| 		minetest.chat_send_all(name .. ": " .. param) | ||||
| @@ -11,7 +9,7 @@ minetest.register_chatcommand("say", { | ||||
|  | ||||
| minetest.register_chatcommand("tell", { | ||||
| 	params = "<name> <text>", | ||||
| 	description = S("Say <text> to <name> privately"), | ||||
| 	description = "Say <text> to <name> privately", | ||||
| 	privs = {shout=true}, | ||||
| 	func = function(name, param) | ||||
| 		local found, _, target, message = param:find("^([^%s]+)%s+(.*)$") | ||||
| @@ -28,7 +26,7 @@ minetest.register_chatcommand("tell", { | ||||
|  | ||||
| minetest.register_chatcommand("hp", { | ||||
| 	params = "<name> <value>", | ||||
| 	description = S("Set health of <name> to <value> hitpoints"), | ||||
| 	description = "Set health of <name> to <value> hitpoints", | ||||
| 	privs = {ban=true}, | ||||
| 	func = function(name, param) | ||||
| 		local found, _, target, value = param:find("^([^%s]+)%s+(%d+)$") | ||||
| @@ -182,7 +180,7 @@ local function can_dig(pos, player) | ||||
| end | ||||
|  | ||||
| minetest.register_node("mesecons_commandblock:commandblock_off", { | ||||
| 	description = S("Command Block"), | ||||
| 	description = "Command Block", | ||||
| 	tiles = {"jeija_commandblock_off.png"}, | ||||
| 	inventory_image = minetest.inventorycube("jeija_commandblock_off.png"), | ||||
| 	is_ground_content = false, | ||||
|   | ||||
| @@ -1,5 +0,0 @@ | ||||
| # textdomain: mesecons_commandblock | ||||
| Say <text> as the server=<Text> als Server sagen | ||||
| Say <text> to <name> privately=<Text> an <Name> privat senden | ||||
| Set health of <name> to <value> hitpoints=Gesundheit von <Name> auf <Wert> Trefferpunkte setzen | ||||
| Command Block=Befehlsblock | ||||
| @@ -1,7 +0,0 @@ | ||||
| # textdomain: mesecons_commandblock | ||||
|  | ||||
| ### init.lua ### | ||||
| Say <text> as the server=Diru <teksto> kiel la servilo | ||||
| Say <text> to <name> privately=Diru <teksto> al <nomo> private | ||||
| Set health of <name> to <value> hitpoints=Agordu sanon de <nomo> al <valoro> | ||||
| Command Block=Komando-Bloko | ||||
| @@ -1,7 +0,0 @@ | ||||
| # textdomain: mesecons_commandblock | ||||
|  | ||||
| ### init.lua ### | ||||
| Say <text> as the server= | ||||
| Say <text> to <name> privately= | ||||
| Set health of <name> to <value> hitpoints= | ||||
| Command Block= | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| -- Function that get the input/output rules of the delayer | ||||
| local delayer_get_output_rules = mesecon.horiz_rules_getter({{x = 1, y = 0, z = 0}}) | ||||
|  | ||||
| @@ -62,8 +60,6 @@ local def = { | ||||
| 	sounds = mesecon.node_sound.stone, | ||||
| 	on_blast = mesecon.on_blastnode, | ||||
| 	drop = "mesecons_delayer:delayer_off_1", | ||||
| 	delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i), | ||||
| 	delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i), | ||||
| } | ||||
|  | ||||
| -- Deactivated delayer definition defaults | ||||
| @@ -73,7 +69,7 @@ if i > 1 then | ||||
| end | ||||
|  | ||||
| local off_state = { | ||||
| 	description = S("Delayer"), | ||||
| 	description = "Delayer", | ||||
| 	tiles = { | ||||
| 		"mesecons_delayer_off_"..tostring(i)..".png", | ||||
| 		"mesecons_delayer_bottom.png", | ||||
| @@ -95,6 +91,7 @@ local off_state = { | ||||
| 			param2 = node.param2 | ||||
| 		}) | ||||
| 	end, | ||||
| 	delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i), | ||||
| 	mesecons = { | ||||
| 		receptor = | ||||
| 		{ | ||||
| @@ -104,7 +101,6 @@ local off_state = { | ||||
| 		effector = | ||||
| 		{ | ||||
| 			rules = delayer_get_input_rules, | ||||
| 			action_off = delayer_deactivate, | ||||
| 			action_on = delayer_activate | ||||
| 		} | ||||
| 	}, | ||||
| @@ -116,7 +112,7 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), off_state) | ||||
|  | ||||
| -- Activated delayer definition defaults | ||||
| local on_state = { | ||||
| 	description = S("You hacker you"), | ||||
| 	description = "You hacker you", | ||||
| 	tiles = { | ||||
| 		"mesecons_delayer_on_"..tostring(i)..".png", | ||||
| 		"mesecons_delayer_bottom.png", | ||||
| @@ -136,6 +132,7 @@ local on_state = { | ||||
| 			param2 = node.param2 | ||||
| 		}) | ||||
| 	end, | ||||
| 	delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i), | ||||
| 	mesecons = { | ||||
| 		receptor = | ||||
| 		{ | ||||
| @@ -145,8 +142,7 @@ local on_state = { | ||||
| 		effector = | ||||
| 		{ | ||||
| 			rules = delayer_get_input_rules, | ||||
| 			action_off = delayer_deactivate, | ||||
| 			action_on = delayer_activate | ||||
| 			action_off = delayer_deactivate | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|   | ||||
| @@ -1,3 +0,0 @@ | ||||
| # textdomain: mesecons_delayer | ||||
| Delayer=Verzögerer | ||||
| You hacker you=Du Hacker, Du | ||||
| @@ -1,5 +0,0 @@ | ||||
| # textdomain: mesecons_delayer | ||||
|  | ||||
| ### init.lua ### | ||||
| Delayer=Prokrasto | ||||
| You hacker you=Vi hakisto | ||||
| @@ -1,5 +0,0 @@ | ||||
| # textdomain: mesecons_delayer | ||||
|  | ||||
| ### init.lua ### | ||||
| Delayer= | ||||
| You hacker you= | ||||
| @@ -1,19 +1,7 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local side_texture = mesecon.texture.steel_block or "mesecons_detector_side.png" | ||||
|  | ||||
| local GET_COMMAND = "GET" | ||||
|  | ||||
|  | ||||
| local function comma_list_to_table(comma_list) | ||||
| 	local tbl = {} | ||||
| 	for _, str in ipairs(string.split(comma_list:gsub("%s", ""), ",")) do | ||||
| 		tbl[str] = true | ||||
| 	end | ||||
| 	return tbl | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Object detector | ||||
| -- Detects players in a certain radius | ||||
| -- The radius can be specified in mesecons/settings.lua | ||||
| @@ -45,7 +33,10 @@ local function object_detector_scan(pos) | ||||
| 	if next(objs) == nil then return false end | ||||
|  | ||||
| 	local scanname = minetest.get_meta(pos):get_string("scanname") | ||||
| 	local scan_for = comma_list_to_table(scanname) | ||||
| 	local scan_for = {} | ||||
| 	for _, str in pairs(string.split(scanname:gsub(" ", ""), ",")) do | ||||
| 		scan_for[str] = true | ||||
| 	end | ||||
|  | ||||
| 	local every_player = scanname == "" | ||||
| 	for _, obj in pairs(objs) do | ||||
| @@ -80,7 +71,7 @@ minetest.register_node("mesecons_detector:object_detector_off", { | ||||
| 	is_ground_content = false, | ||||
| 	walkable = true, | ||||
| 	groups = {cracky=3}, | ||||
| 	description= S("Player Detector"), | ||||
| 	description="Player Detector", | ||||
| 	mesecons = {receptor = { | ||||
| 		state = mesecon.state.off, | ||||
| 		rules = mesecon.rules.pplate | ||||
| @@ -157,23 +148,6 @@ minetest.register_abm({ | ||||
| -- Node detector | ||||
| -- Detects the node in front of it | ||||
|  | ||||
| local blacklist = { | ||||
| 	air = true, | ||||
| 	ignore = true, | ||||
| } | ||||
|  | ||||
| function mesecon.node_detector_blacklist_add(node) | ||||
| 	blacklist[node] = true | ||||
| end | ||||
|  | ||||
| function mesecon.node_detector_blacklist_remove(node) | ||||
| 	blacklist[node] = nil | ||||
| end | ||||
|  | ||||
| function mesecon.node_detector_on_blacklist(node) | ||||
| 	return blacklist[node] == true | ||||
| end | ||||
|  | ||||
| local function node_detector_make_formspec(pos) | ||||
| 	local meta = minetest.get_meta(pos) | ||||
| 	if meta:get_string("distance") == ""  then meta:set_string("distance", "0") end | ||||
| @@ -212,10 +186,9 @@ local function node_detector_scan(pos) | ||||
| 		vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1)) | ||||
| 	).name | ||||
| 	local scanname = meta:get_string("scanname") | ||||
| 	local scan_for = comma_list_to_table(scanname) | ||||
|  | ||||
| 	return (scan_for[frontname]) or | ||||
| 		(blacklist[frontname] ~= true and scanname == "") | ||||
| 	return (frontname == scanname) or | ||||
| 		(frontname ~= "air" and frontname ~= "ignore" and scanname == "") | ||||
| end | ||||
|  | ||||
| local function node_detector_send_node_name(pos, node, channel, meta) | ||||
| @@ -274,7 +247,7 @@ minetest.register_node("mesecons_detector:node_detector_off", { | ||||
| 	is_ground_content = false, | ||||
| 	walkable = true, | ||||
| 	groups = {cracky=3}, | ||||
| 	description = S("Node Detector"), | ||||
| 	description="Node Detector", | ||||
| 	mesecons = {receptor = { | ||||
| 		state = mesecon.state.off | ||||
| 	}}, | ||||
|   | ||||
| @@ -1,3 +0,0 @@ | ||||
| # textdomain: mesecons_detector | ||||
| Player Detector=Spielerdetektor | ||||
| Node Detector=Blockdetektor | ||||
| @@ -1,5 +0,0 @@ | ||||
| # textdomain: mesecons_detector | ||||
|  | ||||
| ### init.lua ### | ||||
| Player Detector=Ludanta Detektilo | ||||
| Node Detector=Noda Detektilo | ||||
| @@ -1,5 +0,0 @@ | ||||
| # textdomain: mesecons_detector | ||||
|  | ||||
| ### init.lua ### | ||||
| Player Detector= | ||||
| Node Detector= | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local corner_selectionbox = { | ||||
| 		type = "fixed", | ||||
| 		fixed = { -16/32, -16/32, -16/32, 5/32, -12/32, 5/32 }, | ||||
| @@ -38,7 +36,7 @@ minetest.register_node("mesecons_extrawires:corner_on", { | ||||
|  | ||||
| minetest.register_node("mesecons_extrawires:corner_off", { | ||||
| 	drawtype = "mesh", | ||||
| 	description = S("Insulated Mesecon Corner"), | ||||
| 	description = "Insulated Mesecon Corner", | ||||
| 	mesh = "mesecons_extrawires_corner.obj", | ||||
| 	tiles = { | ||||
| 		{ name = "jeija_insulated_wire_sides_off.png", backface_culling = true }, | ||||
| @@ -69,9 +67,3 @@ minetest.register_craft({ | ||||
| 		{"", "mesecons_insulated:insulated_off"}, | ||||
| 	} | ||||
| }) | ||||
|  | ||||
| minetest.register_craft({ | ||||
| 	output = "mesecons_insulated:insulated_off", | ||||
| 	type = "shapeless", | ||||
| 	recipe = {"mesecons_extrawires:corner_off"} | ||||
| }) | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local crossover_rules = { | ||||
| 	{--first wire | ||||
| 		{x=-1,y=0,z=0}, | ||||
| @@ -19,7 +17,7 @@ local crossover_states = { | ||||
| } | ||||
|  | ||||
| minetest.register_node("mesecons_extrawires:crossover_off", { | ||||
| 	description = S("Insulated Mesecon Crossover"), | ||||
| 	description = "Insulated Mesecon Crossover", | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "mesecons_extrawires_crossover.b3d", | ||||
| 	tiles = { | ||||
| @@ -45,7 +43,7 @@ minetest.register_node("mesecons_extrawires:crossover_off", { | ||||
| }) | ||||
|  | ||||
| minetest.register_node("mesecons_extrawires:crossover_01", { | ||||
| 	description = S("You hacker you!"), | ||||
| 	description = "You hacker you!", | ||||
| 	drop = "mesecons_extrawires:crossover_off", | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "mesecons_extrawires_crossover.b3d", | ||||
| @@ -72,7 +70,7 @@ minetest.register_node("mesecons_extrawires:crossover_01", { | ||||
| }) | ||||
|  | ||||
| minetest.register_node("mesecons_extrawires:crossover_10", { | ||||
| 	description = S("You hacker you!"), | ||||
| 	description = "You hacker you!", | ||||
| 	drop = "mesecons_extrawires:crossover_off", | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "mesecons_extrawires_crossover.b3d", | ||||
| @@ -99,7 +97,7 @@ minetest.register_node("mesecons_extrawires:crossover_10", { | ||||
| }) | ||||
|  | ||||
| minetest.register_node("mesecons_extrawires:crossover_on", { | ||||
| 	description = S("You hacker you!"), | ||||
| 	description = "You hacker you!", | ||||
| 	drop = "mesecons_extrawires:crossover_off", | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "mesecons_extrawires_crossover.b3d", | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local doublecorner_selectionbox = { | ||||
| 	type = "fixed", | ||||
| 	fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, | ||||
| @@ -33,7 +31,7 @@ for k, state in ipairs(doublecorner_states) do | ||||
| 	minetest.register_node(state, { | ||||
| 		drawtype = "mesh", | ||||
| 		mesh = "mesecons_extrawires_doublecorner.obj", | ||||
| 		description = S("Insulated Mesecon Double Corner"), | ||||
| 		description = "Insulated Mesecon Double Corner", | ||||
| 		tiles = { | ||||
| 			{ name = "jeija_insulated_wire_sides_" .. w1 .. ".png", backface_culling = true }, | ||||
| 			{ name = "jeija_insulated_wire_ends_" .. w1 .. ".png", backface_culling = true }, | ||||
|   | ||||
| @@ -1,8 +0,0 @@ | ||||
| # textdomain: mesecons_extrawires | ||||
| Insulated Mesecon Corner=Isolierte Meseconecke | ||||
| Insulated Mesecon Crossover=Isolierter Meseconübergang | ||||
| You hacker you!=Sie Hacker! | ||||
| Insulated Mesecon Double Corner=Isolierte Mesecondoppelecke | ||||
| Mese Wire=Mesedraht | ||||
| Insulated Mesecon T-junction=Isolierte Mesecongabelung | ||||
| Vertical Mesecon=Vertikaler Mesecon | ||||
| @@ -1,20 +0,0 @@ | ||||
| # textdomain: mesecons_extrawires | ||||
|  | ||||
| ### corner.lua ### | ||||
| Insulated Mesecon Corner=Izolita Mesekonduktila Angulo | ||||
|  | ||||
| ### crossover.lua ### | ||||
| Insulated Mesecon Crossover=Izolita Mesekonduktila Interkruciĝo | ||||
| You hacker you!=Vi hakisto | ||||
|  | ||||
| ### doublecorner.lua ### | ||||
| Insulated Mesecon Double Corner=Izolita Mesekonduktila Duobla Angulo | ||||
|  | ||||
| ### mesewire.lua ### | ||||
| Mese Wire=Mesea Drato | ||||
|  | ||||
| ### tjunction.lua ### | ||||
| Insulated Mesecon T-junction=Izolita Mesekonduktila T-Kruciĝo | ||||
|  | ||||
| ### vertical.lua ### | ||||
| Vertical Mesecon=Vertikala Mesekonduktilo | ||||
| @@ -1,20 +0,0 @@ | ||||
| # textdomain: mesecons_extrawires | ||||
|  | ||||
| ### corner.lua ### | ||||
| Insulated Mesecon Corner= | ||||
|  | ||||
| ### crossover.lua ### | ||||
| Insulated Mesecon Crossover= | ||||
| You hacker you!= | ||||
|  | ||||
| ### doublecorner.lua ### | ||||
| Insulated Mesecon Double Corner= | ||||
|  | ||||
| ### mesewire.lua ### | ||||
| Mese Wire= | ||||
|  | ||||
| ### tjunction.lua ### | ||||
| Insulated Mesecon T-junction= | ||||
|  | ||||
| ### vertical.lua ### | ||||
| Vertical Mesecon= | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local mese_nodename = minetest.registered_aliases["mesecons_gamecompat:mese"] | ||||
| if mese_nodename then | ||||
| 	-- Convert placeholders. | ||||
| @@ -8,7 +6,7 @@ else | ||||
| 	-- Register placeholder. | ||||
| 	mese_nodename = "mesecons_extrawires:mese" | ||||
| 	minetest.register_node("mesecons_extrawires:mese", { | ||||
| 		description = S("Mese Wire"), | ||||
| 		description = "Mese Wire", | ||||
| 		tiles = {"mesecons_wire_off.png"}, | ||||
| 		paramtype = "light", | ||||
| 		light_source = 3, | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local tjunction_nodebox = { | ||||
| 	type = "fixed", | ||||
| 	-- ±0.001 is to prevent z-fighting | ||||
| @@ -50,7 +48,7 @@ minetest.register_node("mesecons_extrawires:tjunction_on", { | ||||
|  | ||||
| minetest.register_node("mesecons_extrawires:tjunction_off", { | ||||
| 	drawtype = "nodebox", | ||||
| 	description = S("Insulated Mesecon T-junction"), | ||||
| 	description = "Insulated Mesecon T-junction", | ||||
| 	tiles = { | ||||
| 		"jeija_insulated_wire_tjunction_tb_off.png", | ||||
| 		"jeija_insulated_wire_tjunction_tb_off.png^[transformR180", | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local vertical_box = { | ||||
| 	type = "fixed", | ||||
| 	fixed = {-1/16, -8/16, -1/16, 1/16, 8/16, 1/16} | ||||
| @@ -40,39 +38,35 @@ local bottom_rules = { | ||||
| 	{x=0, y=2, z=0} -- receive power from pressure plate / detector / ... 2 nodes above | ||||
| } | ||||
|  | ||||
| local function is_vertical_conductor(nodename) | ||||
| 	local def = minetest.registered_nodes[nodename] | ||||
| 	return def and def.is_vertical_conductor | ||||
| end | ||||
|  | ||||
| local vertical_updatepos = function (pos) | ||||
| 	local node = minetest.get_node(pos) | ||||
| 	if not is_vertical_conductor(node.name) then | ||||
| 		return | ||||
| 	if minetest.registered_nodes[node.name] | ||||
| 	and minetest.registered_nodes[node.name].is_vertical_conductor then | ||||
| 		local node_above = minetest.get_node(vector.add(pos, vertical_rules[1])) | ||||
| 		local node_below = minetest.get_node(vector.add(pos, vertical_rules[2])) | ||||
|  | ||||
| 		local above = minetest.registered_nodes[node_above.name] | ||||
| 			and minetest.registered_nodes[node_above.name].is_vertical_conductor | ||||
| 		local below = minetest.registered_nodes[node_below.name] | ||||
| 			and minetest.registered_nodes[node_below.name].is_vertical_conductor | ||||
|  | ||||
| 		mesecon.on_dignode(pos, node) | ||||
|  | ||||
| 		-- Always place offstate conductor and let mesecon.on_placenode take care | ||||
| 		local newname = "mesecons_extrawires:vertical_" | ||||
| 		if above and below then -- above and below: vertical mesecon | ||||
| 			newname = newname .. "off" | ||||
| 		elseif above and not below then -- above only: bottom | ||||
| 			newname = newname .. "bottom_off" | ||||
| 		elseif not above and below then -- below only: top | ||||
| 			newname = newname .. "top_off" | ||||
| 		else -- no vertical wire above, no vertical wire below: use bottom | ||||
| 			newname = newname .. "bottom_off" | ||||
| 		end | ||||
|  | ||||
| 		minetest.set_node(pos, {name = newname}) | ||||
| 		mesecon.on_placenode(pos, {name = newname}) | ||||
| 	end | ||||
|  | ||||
| 	local node_above = minetest.get_node(vector.add(pos, vertical_rules[1])) | ||||
| 	local node_below = minetest.get_node(vector.add(pos, vertical_rules[2])) | ||||
|  | ||||
| 	local above = is_vertical_conductor(node_above.name) | ||||
| 	local below = is_vertical_conductor(node_below.name) | ||||
|  | ||||
| 	mesecon.on_dignode(pos, node) | ||||
|  | ||||
| 	-- Always place offstate conductor and let mesecon.on_placenode take care | ||||
| 	local newname = "mesecons_extrawires:vertical_" | ||||
| 	if above and below then -- above and below: vertical mesecon | ||||
| 		newname = newname .. "off" | ||||
| 	elseif above and not below then -- above only: bottom | ||||
| 		newname = newname .. "bottom_off" | ||||
| 	elseif not above and below then -- below only: top | ||||
| 		newname = newname .. "top_off" | ||||
| 	else -- no vertical wire above, no vertical wire below: use bottom | ||||
| 		newname = newname .. "bottom_off" | ||||
| 	end | ||||
|  | ||||
| 	minetest.set_node(pos, {name = newname}) | ||||
| 	mesecon.on_placenode(pos, {name = newname}) | ||||
| end | ||||
|  | ||||
| local vertical_update = function (pos) | ||||
| @@ -83,7 +77,7 @@ end | ||||
|  | ||||
| -- Vertical wire | ||||
| mesecon.register_node("mesecons_extrawires:vertical", { | ||||
| 	description = S("Vertical Mesecon"), | ||||
| 	description = "Vertical Mesecon", | ||||
| 	drawtype = "nodebox", | ||||
| 	walkable = false, | ||||
| 	paramtype = "light", | ||||
| @@ -116,7 +110,7 @@ mesecon.register_node("mesecons_extrawires:vertical", { | ||||
|  | ||||
| -- Vertical wire top | ||||
| mesecon.register_node("mesecons_extrawires:vertical_top", { | ||||
| 	description = S("Vertical Mesecon"), | ||||
| 	description = "Vertical mesecon", | ||||
| 	drawtype = "nodebox", | ||||
| 	walkable = false, | ||||
| 	paramtype = "light", | ||||
| @@ -148,7 +142,7 @@ mesecon.register_node("mesecons_extrawires:vertical_top", { | ||||
|  | ||||
| -- Vertical wire bottom | ||||
| mesecon.register_node("mesecons_extrawires:vertical_bottom", { | ||||
| 	description = S("Vertical Mesecon"), | ||||
| 	description = "Vertical mesecon", | ||||
| 	drawtype = "nodebox", | ||||
| 	walkable = false, | ||||
| 	paramtype = "light", | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local plg = {} | ||||
| plg.rules = {} | ||||
| -- per-player formspec positions | ||||
| @@ -61,7 +59,7 @@ plg.register_nodes = function(template) | ||||
| end | ||||
|  | ||||
| plg.register_nodes({ | ||||
| 	description = S("FPGA"), | ||||
| 	description = "FPGA", | ||||
| 	drawtype = "nodebox", | ||||
| 	tiles = { | ||||
| 		"", -- replaced later | ||||
|   | ||||
| @@ -1,3 +0,0 @@ | ||||
| # textdomain: mesecons_fpga | ||||
| FPGA=FPGA | ||||
| FPGA Programmer=FPGA-Programmierer | ||||
| @@ -1,7 +0,0 @@ | ||||
| # textdomain: mesecons_fpga | ||||
|  | ||||
| ### init.lua ### | ||||
| FPGA=FPGA | ||||
|  | ||||
| ### tool.lua ### | ||||
| FPGA Programmer=FPGA Programilo | ||||
| @@ -1,7 +0,0 @@ | ||||
| # textdomain: mesecons_fpga | ||||
|  | ||||
| ### init.lua ### | ||||
| FPGA= | ||||
|  | ||||
| ### tool.lua ### | ||||
| FPGA Programmer= | ||||
| @@ -1,106 +0,0 @@ | ||||
| require("mineunit") | ||||
|  | ||||
| fixture("mesecons_fpga") | ||||
| fixture("screwdriver") | ||||
|  | ||||
| local pos = {x = 0, y = 0, z = 0} | ||||
| local pos_a = {x = -1, y = 0, z =  0} | ||||
| local pos_b = {x =  0, y = 0, z =  1} | ||||
| local pos_c = {x =  1, y = 0, z =  0} | ||||
| local pos_d = {x =  0, y = 0, z = -1} | ||||
|  | ||||
| describe("FPGA rotation", function() | ||||
| 	before_each(function() | ||||
| 		world.set_node(pos, "mesecons_fpga:fpga0000") | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("rotates I/O operands clockwise", function() | ||||
| 		mesecon._test_program_fpga(pos, {{"A", "OR", "B", "C"}}) | ||||
|  | ||||
| 		local node = world.get_node(pos) | ||||
| 		minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_FACE) | ||||
|  | ||||
| 		mesecon._test_place(pos_b, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) | ||||
|  | ||||
| 		mesecon._test_dig(pos_b) | ||||
| 		mesecon._test_place(pos_c, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/deactivate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("rotates I/O operands counterclockwise", function() | ||||
| 		mesecon._test_program_fpga(pos, {{"A", "OR", "B", "C"}}) | ||||
|  | ||||
| 		local node = world.get_node(pos) | ||||
| 		minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_AXIS) | ||||
|  | ||||
| 		mesecon._test_place(pos_d, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) | ||||
|  | ||||
| 		mesecon._test_dig(pos_d) | ||||
| 		mesecon._test_place(pos_a, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/deactivate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("updates ports", function() | ||||
| 		mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}}) | ||||
| 		assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) | ||||
|  | ||||
| 		local node = world.get_node(pos) | ||||
| 		minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_AXIS) | ||||
| 		assert.equal("mesecons_fpga:fpga0001", world.get_node(pos).name) | ||||
| 	end) | ||||
| end) | ||||
|  | ||||
| describe("FPGA programmer", function() | ||||
| 	local pos2 = {x = 10, y = 0, z = 0} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		world.set_node(pos, "mesecons_fpga:fpga0000") | ||||
| 		world.set_node(pos2, "mesecons_fpga:fpga0000") | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("transfers instructions", function() | ||||
| 		mesecon._test_program_fpga(pos2, {{"NOT", "A", "B"}}) | ||||
| 		mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2)) | ||||
| 		assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("does not copy from new FPGAs", function() | ||||
| 		mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}}) | ||||
| 		mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2)) | ||||
| 		assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("does not copy from cleared FPGAs", function() | ||||
| 		mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}}) | ||||
| 		mesecon._test_program_fpga(pos2, {{"=", "A", "B"}}) | ||||
| 		mesecon._test_program_fpga(pos2, {}) | ||||
| 		mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2)) | ||||
| 		assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("does not copy from non-FPGA nodes", function() | ||||
| 		mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}}) | ||||
| 		mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(vector.add(pos2, 1))) | ||||
| 		assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) | ||||
| 	end) | ||||
| end) | ||||
| @@ -1,235 +0,0 @@ | ||||
| require("mineunit") | ||||
|  | ||||
| fixture("mesecons_fpga") | ||||
|  | ||||
| describe("FPGA logic", function() | ||||
| 	local pos = {x = 0, y = 0, z = 0} | ||||
| 	local pos_a = {x = -1, y = 0, z =  0} | ||||
| 	local pos_b = {x =  0, y = 0, z =  1} | ||||
| 	local pos_c = {x =  1, y = 0, z =  0} | ||||
| 	local pos_d = {x =  0, y = 0, z = -1} | ||||
|  | ||||
| 	local fpga_set = false | ||||
|  | ||||
| 	local function set_fpga() | ||||
| 		if not fpga_set then | ||||
| 			world.set_node(pos, "mesecons_fpga:fpga0000") | ||||
| 			fpga_set = true | ||||
| 		end | ||||
| 	end | ||||
| 	before_each(set_fpga) | ||||
|  | ||||
| 	local function reset_world() | ||||
| 		if fpga_set then | ||||
| 			mesecon._test_reset() | ||||
| 			world.clear() | ||||
| 			fpga_set = false | ||||
| 		end | ||||
| 	end | ||||
| 	after_each(reset_world) | ||||
|  | ||||
| 	local function test_program(inputs, outputs, program) | ||||
| 		set_fpga() | ||||
|  | ||||
| 		mesecon._test_program_fpga(pos, program) | ||||
|  | ||||
| 		if inputs.a then mesecon._test_place(pos_a, "mesecons:test_receptor_on") end | ||||
| 		if inputs.b then mesecon._test_place(pos_b, "mesecons:test_receptor_on") end | ||||
| 		if inputs.c then mesecon._test_place(pos_c, "mesecons:test_receptor_on") end | ||||
| 		if inputs.d then mesecon._test_place(pos_d, "mesecons:test_receptor_on") end | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
|  | ||||
| 		local expected_name = "mesecons_fpga:fpga" | ||||
| 				.. (outputs.d and 1 or 0) .. (outputs.c and 1 or 0) | ||||
| 				.. (outputs.b and 1 or 0) .. (outputs.a and 1 or 0) | ||||
| 		assert.equal(expected_name, world.get_node(pos).name) | ||||
|  | ||||
| 		reset_world() | ||||
| 	end | ||||
|  | ||||
| 	it("operator and", function() | ||||
| 		local prog = {{"A", "AND", "B", "C"}} | ||||
| 		test_program({}, {}, prog) | ||||
| 		test_program({a = true}, {}, prog) | ||||
| 		test_program({b = true}, {}, prog) | ||||
| 		test_program({a = true, b = true}, {c = true}, prog) | ||||
| 	end) | ||||
|  | ||||
| 	it("operator or", function() | ||||
| 		local prog = {{"A", "OR", "B", "C"}} | ||||
| 		test_program({}, {}, prog) | ||||
| 		test_program({a = true}, {c = true}, prog) | ||||
| 		test_program({b = true}, {c = true}, prog) | ||||
| 		test_program({a = true, b = true}, {c = true}, prog) | ||||
| 	end) | ||||
|  | ||||
| 	it("operator not", function() | ||||
| 		local prog = {{"NOT", "A", "B"}} | ||||
| 		test_program({}, {b = true}, prog) | ||||
| 		test_program({a = true}, {}, prog) | ||||
| 	end) | ||||
|  | ||||
| 	it("operator xor", function() | ||||
| 		local prog = {{"A", "XOR", "B", "C"}} | ||||
| 		test_program({}, {}, prog) | ||||
| 		test_program({a = true}, {c = true}, prog) | ||||
| 		test_program({b = true}, {c = true}, prog) | ||||
| 		test_program({a = true, b = true}, {}, prog) | ||||
| 	end) | ||||
|  | ||||
| 	it("operator nand", function() | ||||
| 		local prog = {{"A", "NAND", "B", "C"}} | ||||
| 		test_program({}, {c = true}, prog) | ||||
| 		test_program({a = true}, {c = true}, prog) | ||||
| 		test_program({b = true}, {c = true}, prog) | ||||
| 		test_program({a = true, b = true}, {}, prog) | ||||
| 	end) | ||||
|  | ||||
| 	it("operator buf", function() | ||||
| 		local prog = {{"=", "A", "B"}} | ||||
| 		test_program({}, {}, prog) | ||||
| 		test_program({a = true}, {b = true}, prog) | ||||
| 	end) | ||||
|  | ||||
| 	it("operator xnor", function() | ||||
| 		local prog = {{"A", "XNOR", "B", "C"}} | ||||
| 		test_program({}, {c = true}, prog) | ||||
| 		test_program({a = true}, {}, prog) | ||||
| 		test_program({b = true}, {}, prog) | ||||
| 		test_program({a = true, b = true}, {c = true}, prog) | ||||
| 	end) | ||||
|  | ||||
| 	it("operator nor", function() | ||||
| 		local prog = {{"A", "NOR", "B", "C"}} | ||||
| 		test_program({}, {c = true}, prog) | ||||
| 		test_program({a = true}, {}, prog) | ||||
| 		test_program({b = true}, {}, prog) | ||||
| 		test_program({a = true, b = true}, {}, prog) | ||||
| 	end) | ||||
|  | ||||
| 	it("rejects duplicate operands", function() | ||||
| 		test_program({a = true}, {}, {{"A", "OR", "A", "B"}}) | ||||
| 		test_program({a = true}, {}, {{"=", "A", "0"}, {"0", "OR", "0", "B"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("rejects unassigned memory operands", function() | ||||
| 		test_program({a = true}, {}, {{"A", "OR", "0", "B"}}) | ||||
| 		test_program({a = true}, {}, {{"0", "OR", "A", "B"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("rejects double memory assignment", function() | ||||
| 		test_program({a = true}, {}, {{"=", "A", "0"}, {"=", "A", "0"}, {"=", "0", "B"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("rejects assignment to memory operand", function() | ||||
| 		test_program({a = true}, {}, {{"=", "A", "0"}, {"A", "OR", "0", "0"}, {"=", "0", "B"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("allows double port assignment", function() | ||||
| 		test_program({a = true}, {b = true}, {{"NOT", "A", "B"}, {"=", "A", "B"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("allows assignment to port operand", function() | ||||
| 		test_program({a = true}, {b = true}, {{"A", "OR", "B", "B"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("preserves initial pin states", function() | ||||
| 		test_program({a = true}, {b = true}, {{"=", "A", "B"}, {"=", "B", "C"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("rejects binary operations with single operands", function() | ||||
| 		test_program({a = true}, {}, {{"=", "A", "B"}, {" ", "OR", "A", "C"}}) | ||||
| 		test_program({a = true}, {}, {{"=", "A", "B"}, {"A", "OR", " ", "C"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("rejects unary operations with first operands", function() | ||||
| 		test_program({a = true}, {}, {{"=", "A", "B"}, {"A", "=", " ", "C"}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("rejects operations without destinations", function() | ||||
| 		test_program({a = true}, {}, {{"=", "A", "B"}, {"=", "A", " "}}) | ||||
| 	end) | ||||
|  | ||||
| 	it("allows blank statements", function() | ||||
| 		test_program({a = true}, {b = true, c = true}, { | ||||
| 			{" ", " ", " ", " "}, | ||||
| 			{"=", "A", "B"}, | ||||
| 			{" ", " ", " ", " "}, | ||||
| 			{" ", " ", " ", " "}, | ||||
| 			{"=", "A", "C"}, | ||||
| 		}) | ||||
| 	end) | ||||
|  | ||||
| 	it("transmits output signals to adjacent nodes", function() | ||||
| 		mesecon._test_program_fpga(pos, { | ||||
| 			{"=", "A", "B"}, | ||||
| 			{"=", "A", "C"}, | ||||
| 			{"NOT", "A", "D"}, | ||||
| 		}) | ||||
| 		mesecon._test_place(pos_b, "mesecons:test_effector") | ||||
| 		mesecon._test_place(pos_c, "mesecons:test_effector") | ||||
| 		mesecon._test_place(pos_d, "mesecons:test_effector") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
|  | ||||
| 		-- Makes an object from the last three effector events in the list for use with assert.same. | ||||
| 		-- This is necessary to ignore the ordering of events. | ||||
| 		local function event_tester(list) | ||||
| 			local o = {list[#list - 2], list[#list - 1], list[#list - 0]} | ||||
| 			table.sort(o, function(a, b) | ||||
| 				local fmt = "%s %d %d %d" | ||||
| 				return fmt:format(a[1], a[2].x, a[2].y, a[2].z) < fmt:format(b[1], b[2].x, b[2].y, b[2].z) | ||||
| 			end) | ||||
| 			return o | ||||
| 		end | ||||
|  | ||||
| 		mesecon._test_place(pos_a, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/deactivate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga0110", world.get_node(pos).name) | ||||
| 		assert.same(event_tester({{"on", pos_b}, {"on", pos_c}, {"off", pos_d}}), event_tester(mesecon._test_effector_events)) | ||||
|  | ||||
| 		mesecon._test_dig(pos_a) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/deactivate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) | ||||
| 		assert.same(event_tester({{"off", pos_b}, {"off", pos_c}, {"on", pos_d}}), event_tester(mesecon._test_effector_events)) | ||||
| 	end) | ||||
|  | ||||
| 	it("considers past outputs in determining inputs", function() | ||||
| 		-- Memory cell: Turning on A turns on C; turning on B turns off C. | ||||
| 		mesecon._test_program_fpga(pos, { | ||||
| 			{"A", "OR", "C", "0"}, | ||||
| 			{"B", "OR", "D", "1"}, | ||||
| 			{"NOT", "A", "2"}, | ||||
| 			{"NOT", "B", "3"}, | ||||
| 			{"0", "AND", "3", "C"}, | ||||
| 			{"1", "AND", "2", "D"}, | ||||
| 		}) | ||||
|  | ||||
| 		mesecon._test_place(pos_a, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga0100", world.get_node(pos).name) | ||||
|  | ||||
| 		mesecon._test_dig(pos_a) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga0100", world.get_node(pos).name) | ||||
|  | ||||
| 		mesecon._test_place(pos_b, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) | ||||
|  | ||||
| 		mesecon._test_dig(pos_b) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) | ||||
| 	end) | ||||
| end) | ||||
| @@ -1 +0,0 @@ | ||||
| fixture_paths = {"../.test_fixtures"} | ||||
| @@ -1,10 +1,8 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| return function(plg) | ||||
|  | ||||
|  | ||||
| minetest.register_tool("mesecons_fpga:programmer", { | ||||
| 	description = S("FPGA Programmer"), | ||||
| 	description = "FPGA Programmer", | ||||
| 	inventory_image = "jeija_fpga_programmer.png", | ||||
| 	stack_max = 1, | ||||
| 	on_place = function(itemstack, placer, pointed_thing) | ||||
| @@ -23,7 +21,7 @@ minetest.register_tool("mesecons_fpga:programmer", { | ||||
| 			minetest.sound_play("mesecons_fpga_fail", { pos = placer:get_pos(), gain = 0.1, max_hear_distance = 4 }, true) | ||||
| 			return itemstack | ||||
| 		end | ||||
| 		itemstack:get_meta():set_string("", meta:get_string("instr")) | ||||
| 		itemstack:set_metadata(meta:get_string("instr")) | ||||
| 		minetest.chat_send_player(placer:get_player_name(), "FPGA gate configuration was successfully copied!") | ||||
| 		minetest.sound_play("mesecons_fpga_copy", { pos = placer:get_pos(), gain = 0.1, max_hear_distance = 4 }, true) | ||||
|  | ||||
| @@ -44,7 +42,7 @@ minetest.register_tool("mesecons_fpga:programmer", { | ||||
| 			return itemstack | ||||
| 		end | ||||
|  | ||||
| 		local imeta = itemstack:get_meta():get_string("") | ||||
| 		local imeta = itemstack:get_metadata() | ||||
| 		if imeta == "" then | ||||
| 			minetest.chat_send_player(player_name, "Use shift+right-click to copy a gate configuration first.") | ||||
| 			minetest.sound_play("mesecons_fpga_fail", { pos = user:get_pos(), gain = 0.1, max_hear_distance = 4 }, true) | ||||
|   | ||||
| @@ -59,10 +59,6 @@ if minetest.get_modpath("mesecons_mvps") then | ||||
| 		"doors:hidden", | ||||
| 		"doors:trapdoor_steel", | ||||
| 		"doors:trapdoor_steel_open", | ||||
| 		"beds:bed_bottom", | ||||
| 		"beds:bed_top", | ||||
| 		"beds:fancy_bed_bottom", | ||||
| 		"beds:fancy_bed_top", | ||||
| 		"xpanes:door_steel_bar_a", | ||||
| 		"xpanes:door_steel_bar_b", | ||||
| 		"xpanes:door_steel_bar_c", | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| -- HYDRO_TURBINE | ||||
| -- Water turbine: | ||||
| -- Active if flowing >water< above it | ||||
| @@ -19,7 +17,7 @@ minetest.register_node("mesecons_hydroturbine:hydro_turbine_off", { | ||||
| 	is_ground_content = false, | ||||
| 	wield_scale = {x=0.75, y=0.75, z=0.75}, | ||||
| 	groups = {dig_immediate=2}, | ||||
| 	description = S("Water Turbine"), | ||||
| 	description="Water Turbine", | ||||
| 	paramtype = "light", | ||||
| 	selection_box = { | ||||
| 		type = "fixed", | ||||
| @@ -49,7 +47,7 @@ minetest.register_node("mesecons_hydroturbine:hydro_turbine_on", { | ||||
| 	inventory_image = "jeija_hydro_turbine_inv.png", | ||||
| 	drop = "mesecons_hydroturbine:hydro_turbine_off 1", | ||||
| 	groups = {dig_immediate=2,not_in_creative_inventory=1}, | ||||
| 	description = S("Water Turbine"), | ||||
| 	description="Water Turbine", | ||||
| 	paramtype = "light", | ||||
| 	selection_box = { | ||||
| 		type = "fixed", | ||||
| @@ -99,8 +97,9 @@ nodenames = {"mesecons_hydroturbine:hydro_turbine_on"}, | ||||
| minetest.register_craft({ | ||||
| 	output = "mesecons_hydroturbine:hydro_turbine_off 2", | ||||
| 	recipe = { | ||||
| 	{"","group:stick", ""}, | ||||
| 	{"","grup:stick", ""}, | ||||
| 	{"group:stick", "mesecons_gamecompat:steel_ingot", "group:stick"}, | ||||
| 	{"","group:stick", ""}, | ||||
| 	} | ||||
| }) | ||||
|  | ||||
|   | ||||
| @@ -1,2 +0,0 @@ | ||||
| # textdomain: mesecons_hydroturbine | ||||
| Water Turbine=Wasserturbine | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_hydroturbine | ||||
|  | ||||
| ### init.lua ### | ||||
| Water Turbine=Akva Turbino | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_hydroturbine | ||||
|  | ||||
| ### init.lua ### | ||||
| Water Turbine= | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local insulated_wire_get_rules = mesecon.horiz_rules_getter({ | ||||
| 	{x = 1, y = 0, z = 0}, | ||||
| 	{x = -1, y = 0, z = 0}, | ||||
| @@ -7,7 +5,7 @@ local insulated_wire_get_rules = mesecon.horiz_rules_getter({ | ||||
|  | ||||
| minetest.register_node("mesecons_insulated:insulated_on", { | ||||
| 	drawtype = "nodebox", | ||||
| 	description = S("Straight Insulated Mesecon"), | ||||
| 	description = "Straight Insulated Mesecon", | ||||
| 	tiles = { | ||||
| 		"jeija_insulated_wire_sides_on.png", | ||||
| 		"jeija_insulated_wire_sides_on.png", | ||||
| @@ -44,7 +42,7 @@ minetest.register_node("mesecons_insulated:insulated_on", { | ||||
|  | ||||
| minetest.register_node("mesecons_insulated:insulated_off", { | ||||
| 	drawtype = "nodebox", | ||||
| 	description = S("Straight Insulated Mesecon"), | ||||
| 	description = "Straight Insulated Mesecon", | ||||
| 	tiles = { | ||||
| 		"jeija_insulated_wire_sides_off.png", | ||||
| 		"jeija_insulated_wire_sides_off.png", | ||||
|   | ||||
| @@ -1,2 +0,0 @@ | ||||
| # textdomain: mesecons_insulated | ||||
| Straight Insulated Mesecon=Isolierte Mesecongerade | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_insulated | ||||
|  | ||||
| ### init.lua ### | ||||
| Straight Insulated Mesecon=Rekta Izolita Mesekonduktilo | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_insulated | ||||
|  | ||||
| ### init.lua ### | ||||
| Straight Insulated Mesecon= | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| -- MESELAMPS | ||||
| -- A lamp is "is an electrical device used to create artificial light" (wikipedia) | ||||
| -- guess what? | ||||
| @@ -52,7 +50,7 @@ minetest.register_node("mesecons_lamp:lamp_off", { | ||||
| 	node_box = mesecon_lamp_box, | ||||
| 	selection_box = mesecon_lamp_box, | ||||
| 	groups = {dig_immediate=3, mesecon_receptor_off = 1, mesecon_effector_off = 1}, | ||||
| 	description = S("Mesecon Lamp"), | ||||
| 	description = "Mesecon Lamp", | ||||
| 	sounds = mesecon.node_sound.glass, | ||||
| 	mesecons = {effector = { | ||||
| 		action_on = function (pos, node) | ||||
|   | ||||
| @@ -1,2 +0,0 @@ | ||||
| # textdomain: mesecons_lamp | ||||
| Mesecon Lamp=Meseconlampe | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_lamp | ||||
|  | ||||
| ### init.lua ### | ||||
| Mesecon Lamp=Mesekonduktila Lampo | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_lamp | ||||
|  | ||||
| ### init.lua ### | ||||
| Mesecon Lamp= | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local lightstone_rules = { | ||||
| 	{x=0,  y=0,  z=-1}, | ||||
| 	{x=1,  y=0,  z=0}, | ||||
| @@ -61,15 +59,15 @@ function mesecon.lightstone_add(name, base_item, texture_off, texture_on, desc) | ||||
| end | ||||
|  | ||||
|  | ||||
| mesecon.lightstone_add("red", "mesecons_gamecompat:dye_red", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png", S("Red Lightstone")) | ||||
| mesecon.lightstone_add("green", "mesecons_gamecompat:dye_green", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png", S("Green Lightstone")) | ||||
| mesecon.lightstone_add("blue", "mesecons_gamecompat:dye_blue", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png", S("Blue Lightstone")) | ||||
| mesecon.lightstone_add("gray", "mesecons_gamecompat:dye_grey", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png", S("Grey Lightstone")) | ||||
| mesecon.lightstone_add("darkgray", "mesecons_gamecompat:dye_dark_grey", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png", S("Dark Grey Lightstone")) | ||||
| mesecon.lightstone_add("yellow", "mesecons_gamecompat:dye_yellow", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png", S("Yellow Lightstone")) | ||||
| mesecon.lightstone_add("orange", "mesecons_gamecompat:dye_orange", "jeija_lightstone_orange_off.png", "jeija_lightstone_orange_on.png", S("Orange Lightstone")) | ||||
| mesecon.lightstone_add("white", "mesecons_gamecompat:dye_white", "jeija_lightstone_white_off.png", "jeija_lightstone_white_on.png", S("White Lightstone")) | ||||
| mesecon.lightstone_add("pink", "mesecons_gamecompat:dye_pink", "jeija_lightstone_pink_off.png", "jeija_lightstone_pink_on.png", S("Pink Lightstone")) | ||||
| mesecon.lightstone_add("magenta", "mesecons_gamecompat:dye_magenta", "jeija_lightstone_magenta_off.png", "jeija_lightstone_magenta_on.png", S("Magenta Lightstone")) | ||||
| mesecon.lightstone_add("cyan", "mesecons_gamecompat:dye_cyan", "jeija_lightstone_cyan_off.png", "jeija_lightstone_cyan_on.png", S("Cyan Lightstone")) | ||||
| mesecon.lightstone_add("violet", "mesecons_gamecompat:dye_violet", "jeija_lightstone_violet_off.png", "jeija_lightstone_violet_on.png", S("Violet Lightstone")) | ||||
| mesecon.lightstone_add("red", "mesecons_gamecompat:dye_red", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png", "Red Lightstone") | ||||
| mesecon.lightstone_add("green", "mesecons_gamecompat:dye_green", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png", "Green Lightstone") | ||||
| mesecon.lightstone_add("blue", "mesecons_gamecompat:dye_blue", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png", "Blue Lightstone") | ||||
| mesecon.lightstone_add("gray", "mesecons_gamecompat:dye_grey", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png", "Grey Lightstone") | ||||
| mesecon.lightstone_add("darkgray", "mesecons_gamecompat:dye_dark_grey", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png", "Dark Grey Lightstone") | ||||
| mesecon.lightstone_add("yellow", "mesecons_gamecompat:dye_yellow", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png", "Yellow Lightstone") | ||||
| mesecon.lightstone_add("orange", "mesecons_gamecompat:dye_orange", "jeija_lightstone_orange_off.png", "jeija_lightstone_orange_on.png", "Orange Lightstone") | ||||
| mesecon.lightstone_add("white", "mesecons_gamecompat:dye_white", "jeija_lightstone_white_off.png", "jeija_lightstone_white_on.png", "White Lightstone") | ||||
| mesecon.lightstone_add("pink", "mesecons_gamecompat:dye_pink", "jeija_lightstone_pink_off.png", "jeija_lightstone_pink_on.png", "Pink Lightstone") | ||||
| mesecon.lightstone_add("magenta", "mesecons_gamecompat:dye_magenta", "jeija_lightstone_magenta_off.png", "jeija_lightstone_magenta_on.png", "Magenta Lightstone") | ||||
| mesecon.lightstone_add("cyan", "mesecons_gamecompat:dye_cyan", "jeija_lightstone_cyan_off.png", "jeija_lightstone_cyan_on.png", "Cyan Lightstone") | ||||
| mesecon.lightstone_add("violet", "mesecons_gamecompat:dye_violet", "jeija_lightstone_violet_off.png", "jeija_lightstone_violet_on.png", "Violet Lightstone") | ||||
|   | ||||
| @@ -1,13 +0,0 @@ | ||||
| # textdomain: mesecons_lightstone | ||||
| Red Lightstone=Roter Leuchtstein | ||||
| Green Lightstone=Grüner Leuchtstein | ||||
| Blue Lightstone=Blauer Leuchtstein | ||||
| Grey Lightstone=Grauer Leuchtstein | ||||
| Dark Grey Lightstone=Dunkelgrauer Leuchtstein | ||||
| Yellow Lightstone=Gelber Leuchtstein | ||||
| Orange Lightstone=Orange Leuchtstein | ||||
| White Lightstone=Weißer Leuchtstein | ||||
| Pink Lightstone=Rosa Leuchtstein | ||||
| Magenta Lightstone=Magenta Leuchtstein | ||||
| Cyan Lightstone=Türkiser Leuchtstein | ||||
| Violet Lightstone=Violetter Leuchtstein | ||||
| @@ -1,15 +0,0 @@ | ||||
| # textdomain: mesecons_lightstone | ||||
|  | ||||
| ### init.lua ### | ||||
| Red Lightstone=Ruĝa Lumŝtono | ||||
| Green Lightstone=Verda Lumŝtono | ||||
| Blue Lightstone=Blua Lumŝtono | ||||
| Grey Lightstone=Griza Lumŝtono | ||||
| Dark Grey Lightstone=Malhela Griza Lumŝtono | ||||
| Yellow Lightstone=Flava Lumŝtono | ||||
| Orange Lightstone=Oranĝa Lumŝtono | ||||
| White Lightstone=Blanka Lumŝtono | ||||
| Pink Lightstone=Rozkolora Lumŝtono | ||||
| Magenta Lightstone=Magenta Lumŝtono | ||||
| Cyan Lightstone=Cejana Lumŝtono | ||||
| Violet Lightstone=Viola Lumŝtono | ||||
| @@ -1,15 +0,0 @@ | ||||
| # textdomain: mesecons_lightstone | ||||
|  | ||||
| ### init.lua ### | ||||
| Red Lightstone= | ||||
| Green Lightstone= | ||||
| Blue Lightstone= | ||||
| Grey Lightstone= | ||||
| Dark Grey Lightstone= | ||||
| Yellow Lightstone= | ||||
| Orange Lightstone= | ||||
| White Lightstone= | ||||
| Pink Lightstone= | ||||
| Magenta Lightstone= | ||||
| Cyan Lightstone= | ||||
| Violet Lightstone= | ||||
| @@ -28,8 +28,6 @@ | ||||
| -- (see where local env is defined) | ||||
| -- Something nice to play is is appending minetest.env to it. | ||||
|  | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local BASENAME = "mesecons_luacontroller:luacontroller" | ||||
|  | ||||
| local rules = { | ||||
| @@ -203,13 +201,11 @@ end | ||||
| ------------------------- | ||||
|  | ||||
| local function safe_print(param) | ||||
| 	if mesecon.setting("luacontroller_print_behavior", "log") == "log" then | ||||
| 		local string_meta = getmetatable("") | ||||
| 		local sandbox = string_meta.__index | ||||
| 		string_meta.__index = string -- Leave string sandbox temporarily | ||||
| 		minetest.log("action", string.format("[mesecons_luacontroller] print(%s)", dump(param))) | ||||
| 		string_meta.__index = sandbox -- Restore string sandbox | ||||
| 	end | ||||
| 	local string_meta = getmetatable("") | ||||
| 	local sandbox = string_meta.__index | ||||
| 	string_meta.__index = string -- Leave string sandbox temporarily | ||||
| 	print(dump(param)) | ||||
| 	string_meta.__index = sandbox -- Restore string sandbox | ||||
| end | ||||
|  | ||||
| local function safe_date() | ||||
| @@ -238,16 +234,6 @@ local function safe_string_find(...) | ||||
| 	return string.find(...) | ||||
| end | ||||
|  | ||||
| -- do not allow pattern matching in string.split (see string.find for details) | ||||
| local function safe_string_split(...) | ||||
| 	if select(5, ...) then | ||||
| 		debug.sethook() -- Clear hook | ||||
| 		error("string.split: 'sep_is_pattern' (fifth parameter) may not be used in a Luacontroller") | ||||
| 	end | ||||
|  | ||||
| 	return string.split(...) | ||||
| end | ||||
|  | ||||
| local function remove_functions(x) | ||||
| 	local tp = type(x) | ||||
| 	if tp == "function" then | ||||
| @@ -388,10 +374,7 @@ local function clean_and_weigh_digiline_message(msg, back_references) | ||||
| 		return msg, #msg + 25 | ||||
| 	elseif t == "number" then | ||||
| 		-- Numbers are passed by value so need not be touched, and cost 8 bytes | ||||
| 		-- as all numbers in Lua are doubles. NaN values are removed. | ||||
| 		if msg ~= msg then | ||||
| 			return nil, 0 | ||||
| 		end | ||||
| 		-- as all numbers in Lua are doubles. | ||||
| 		return msg, 8 | ||||
| 	elseif t == "boolean" then | ||||
| 		-- Booleans are passed by value so need not be touched, and cost 1 | ||||
| @@ -520,7 +503,6 @@ local function create_environment(pos, mem, event, itbl, send_warning) | ||||
| 			reverse = string.reverse, | ||||
| 			sub = string.sub, | ||||
| 			find = safe_string_find, | ||||
| 			split = safe_string_split, | ||||
| 		}, | ||||
| 		math = { | ||||
| 			abs = math.abs, | ||||
| @@ -869,7 +851,7 @@ for d = 0, 1 do | ||||
| 	} | ||||
|  | ||||
| 	minetest.register_node(node_name, { | ||||
| 		description = S("Luacontroller"), | ||||
| 		description = "Luacontroller", | ||||
| 		drawtype = "nodebox", | ||||
| 		tiles = { | ||||
| 			top, | ||||
|   | ||||
| @@ -1,2 +0,0 @@ | ||||
| # textdomain: mesecons_luacontroller | ||||
| Luacontroller=Luacontroller | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_luacontroller | ||||
|  | ||||
| ### init.lua ### | ||||
| Luacontroller=Luaregilo | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_luacontroller | ||||
|  | ||||
| ### init.lua ### | ||||
| Luacontroller= | ||||
| @@ -1,38 +0,0 @@ | ||||
| require("mineunit") | ||||
|  | ||||
| -- This test is done in a separate file since it requires different configuration at startup. | ||||
| mineunit("core") | ||||
| minetest.settings:set("mesecon.luacontroller_lightweight_interrupts", "true") | ||||
|  | ||||
| fixture("mesecons_luacontroller") | ||||
|  | ||||
| describe("LuaController lightweight interrupt", function() | ||||
| 	local pos = {x = 0, y = 0, z = 0} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		mesecon._test_place(pos, "mesecons_luacontroller:luacontroller0000") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("works", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			if event.type == "program" then | ||||
| 				interrupt(5) | ||||
| 				interrupt(10) | ||||
| 			elseif event.type == "interrupt" then | ||||
| 				port.a = not pin.a | ||||
| 			end | ||||
| 		]]) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		mineunit:execute_globalstep(9) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 		mineunit:execute_globalstep(1) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) | ||||
| 	end) | ||||
| end) | ||||
| @@ -1,176 +0,0 @@ | ||||
| require("mineunit") | ||||
|  | ||||
| fixture("mesecons_luacontroller") | ||||
|  | ||||
| -- Digiline is not tested, since that would require the digiline mod. | ||||
|  | ||||
| describe("LuaController", function() | ||||
| 	local pos = {x = 0, y = 0, z = 0} | ||||
| 	local pos_a = {x = -1, y = 0, z = 0} | ||||
|  | ||||
| 	before_each(function() | ||||
| 		mesecon._test_place(pos, "mesecons_luacontroller:luacontroller0000") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("rejects binary code", function() | ||||
| 		local ok = mesecon._test_program_luac(pos, string.dump(function() end)) | ||||
| 		assert.is_false(ok) | ||||
| 	end) | ||||
|  | ||||
| 	it("I/O", function() | ||||
| 		mesecon._test_place(pos_a, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			port.a = not pin.a | ||||
| 			port.b = not pin.b | ||||
| 			port.c = not pin.c | ||||
| 			port.d = not pin.d | ||||
| 		]]) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller1110", world.get_node(pos).name) | ||||
| 		mesecon._test_dig(pos_a) | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		mineunit:execute_globalstep() -- Execute deactivate/change actions | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("memory", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			if not mem.x then | ||||
| 				mem.x = {} | ||||
| 				mem.x[mem.x] = {true, "", 1.2} | ||||
| 			else | ||||
| 				local b, s, n = unpack(mem.x[mem.x]) | ||||
| 				if b == true and s == "" and n == 1.2 then | ||||
| 					port.d = true | ||||
| 				end | ||||
| 			end | ||||
| 		]]) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 		mesecon._test_place(pos_a, "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller1000", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("interrupts without IDs", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			if event.type == "program" then | ||||
| 				interrupt(4) | ||||
| 				interrupt(8) | ||||
| 			elseif event.type == "interrupt" then | ||||
| 				port.a = not pin.a | ||||
| 			end | ||||
| 		]]) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		mineunit:execute_globalstep(3) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 		mineunit:execute_globalstep(1) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) | ||||
| 		mineunit:execute_globalstep(3) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) | ||||
| 		mineunit:execute_globalstep(1) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("interrupts with IDs", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			if event.type == "program" then | ||||
| 				interrupt(2, "a") | ||||
| 				interrupt(4, "a") | ||||
| 				interrupt(16, "b") | ||||
| 			elseif event.type == "interrupt" then | ||||
| 				if event.iid == "a" then | ||||
| 					interrupt(5, "b") | ||||
| 					interrupt(4, "b") | ||||
| 				end | ||||
| 				port.a = not pin.a | ||||
| 			end | ||||
| 		]]) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		mineunit:execute_globalstep(3) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 		mineunit:execute_globalstep(1) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) | ||||
| 		mineunit:execute_globalstep(3) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) | ||||
| 		mineunit:execute_globalstep(1) | ||||
| 		mineunit:execute_globalstep(0.1) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("limits interrupt ID size", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			if event.type == "program" then | ||||
| 				interrupt(0, (" "):rep(257)) | ||||
| 			elseif event.type == "interrupt" then | ||||
| 				port.a = not pin.a | ||||
| 			end | ||||
| 		]]) | ||||
| 		mineunit:execute_globalstep(3) | ||||
| 		mineunit:execute_globalstep(3) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("string.rep", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			(" "):rep(64000) | ||||
| 			port.a = true | ||||
| 		]]) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			(" "):rep(64001) | ||||
| 			port.b = true | ||||
| 		]]) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("string.find", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			port.a = (" a"):find("a", nil, true) == 2 | ||||
| 		]]) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			(" a"):find("a", nil) | ||||
| 			port.b = true | ||||
| 		]]) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("overheats", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			interrupt(0) | ||||
| 			interrupt(0) | ||||
| 		]]) | ||||
| 		mineunit:execute_globalstep() -- Execute 2 interrupts | ||||
| 		mineunit:execute_globalstep() -- Execute 4 interrupts | ||||
| 		mineunit:execute_globalstep() -- Execute 8 interrupts | ||||
| 		mineunit:execute_globalstep() -- Execute 16 interrupts | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller_burnt", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("limits memory", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			port.a = true | ||||
| 			mem.x = (" "):rep(50000) .. (" "):rep(50000) | ||||
| 		]]) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller_burnt", world.get_node(pos).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("limits run time", function() | ||||
| 		mesecon._test_program_luac(pos, [[ | ||||
| 			port.a = true | ||||
| 			for i = 1, 1000000 do end | ||||
| 		]]) | ||||
| 		assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) | ||||
| 	end) | ||||
| end) | ||||
| @@ -1 +0,0 @@ | ||||
| fixture_paths = {"../.test_fixtures"} | ||||
| @@ -1,16 +1,14 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| -- Glue and fiber | ||||
| minetest.register_craftitem("mesecons_materials:glue", { | ||||
| 	image = "mesecons_glue.png", | ||||
| 	on_place_on_ground = minetest.craftitem_place_item, | ||||
| 	description = S("Glue"), | ||||
| 	description="Glue", | ||||
| }) | ||||
|  | ||||
| minetest.register_craftitem("mesecons_materials:fiber", { | ||||
| 	image = "mesecons_fiber.png", | ||||
| 	on_place_on_ground = minetest.craftitem_place_item, | ||||
| 	description = S("Fiber"), | ||||
| 	description="Fiber", | ||||
| }) | ||||
|  | ||||
| minetest.register_craft({ | ||||
| @@ -31,7 +29,7 @@ minetest.register_craft({ | ||||
| minetest.register_craftitem("mesecons_materials:silicon", { | ||||
| 	image = "mesecons_silicon.png", | ||||
| 	on_place_on_ground = minetest.craftitem_place_item, | ||||
| 	description = S("Silicon"), | ||||
| 	description="Silicon", | ||||
| }) | ||||
|  | ||||
| minetest.register_craft({ | ||||
|   | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_materials | ||||
| Glue=Klebstoff | ||||
| Fiber=Faser | ||||
| Silicon=Silizium | ||||
| @@ -1,6 +0,0 @@ | ||||
| # textdomain: mesecons_materials | ||||
|  | ||||
| ### init.lua ### | ||||
| Glue=Gluo | ||||
| Fiber=Fibro | ||||
| Silicon=Silicio | ||||
| @@ -1,6 +0,0 @@ | ||||
| # textdomain: mesecons_materials | ||||
|  | ||||
| ### init.lua ### | ||||
| Glue= | ||||
| Fiber= | ||||
| Silicon= | ||||
| @@ -1,5 +1,3 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| local EEPROM_SIZE = 255 | ||||
|  | ||||
| local microc_rules = {} | ||||
| @@ -59,7 +57,7 @@ if nodename ~= "mesecons_microcontroller:microcontroller0000" then | ||||
| end | ||||
|  | ||||
| minetest.register_node(nodename, { | ||||
| 	description = S("Microcontroller"), | ||||
| 	description = "Microcontroller", | ||||
| 	drawtype = "nodebox", | ||||
| 	tiles = { | ||||
| 		top, | ||||
|   | ||||
| @@ -1,2 +0,0 @@ | ||||
| # textdomain: mesecons_microcontroller | ||||
| Microcontroller=Mikrocontroller | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_microcontroller | ||||
|  | ||||
| ### init.lua ### | ||||
| Microcontroller=Mikroregilo | ||||
| @@ -1,4 +0,0 @@ | ||||
| # textdomain: mesecons_microcontroller | ||||
|  | ||||
| ### init.lua ### | ||||
| Microcontroller= | ||||
| @@ -8,8 +8,6 @@ | ||||
| -- Pushes all block in front of it | ||||
| -- Pull all blocks in its back | ||||
|  | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| -- settings: | ||||
| local timer_interval = 1 / mesecon.setting("movestone_speed", 3) | ||||
| local max_push = mesecon.setting("movestone_max_push", 50) | ||||
| @@ -130,7 +128,7 @@ mesecon.register_movestone("mesecons_movestones:movestone", { | ||||
| 		"jeija_movestone_arrows.png", | ||||
| 	}, | ||||
| 	groups = {cracky = 3}, | ||||
|     description = S("Movestone"), | ||||
|     description = "Movestone", | ||||
| 	sounds = mesecon.node_sound.stone | ||||
| }, false, false) | ||||
|  | ||||
| @@ -144,7 +142,7 @@ mesecon.register_movestone("mesecons_movestones:sticky_movestone", { | ||||
| 		"jeija_sticky_movestone.png", | ||||
| 	}, | ||||
| 	groups = {cracky = 3}, | ||||
|     description = S("Sticky Movestone"), | ||||
|     description = "Sticky Movestone", | ||||
| 	sounds = mesecon.node_sound.stone, | ||||
| }, true, false) | ||||
|  | ||||
| @@ -158,7 +156,7 @@ mesecon.register_movestone("mesecons_movestones:movestone_vertical", { | ||||
| 		"jeija_movestone_arrows.png^[transformR90", | ||||
| 	}, | ||||
| 	groups = {cracky = 3}, | ||||
|     description = S("Vertical Movestone"), | ||||
|     description = "Vertical Movestone", | ||||
| 	sounds = mesecon.node_sound.stone | ||||
| }, false, true) | ||||
|  | ||||
| @@ -172,7 +170,7 @@ mesecon.register_movestone("mesecons_movestones:sticky_movestone_vertical", { | ||||
| 		"jeija_movestone_arrows.png^[transformR90", | ||||
| 	}, | ||||
| 	groups = {cracky = 3}, | ||||
|     description = S("Vertical Sticky Movestone"), | ||||
|     description = "Vertical Sticky Movestone", | ||||
| 	sounds = mesecon.node_sound.stone, | ||||
| }, true, true) | ||||
|  | ||||
|   | ||||
| @@ -1,5 +0,0 @@ | ||||
| # textdomain: mesecons_movestones | ||||
| Movestone=Laufstein | ||||
| Sticky Movestone=Klebriger Laufstein | ||||
| Vertical Movestone=Vertikaler Laufstein | ||||
| Vertical Sticky Movestone=Vertikaler klebriger Laufstein | ||||
| @@ -1,7 +0,0 @@ | ||||
| # textdomain: mesecons_movestones | ||||
|  | ||||
| ### init.lua ### | ||||
| Movestone=Movŝtono | ||||
| Sticky Movestone=Glueca Movŝtono | ||||
| Vertical Movestone=Vertikala Movŝtono | ||||
| Vertical Sticky Movestone=Vertikala Glueca Movŝtono | ||||
| @@ -1,7 +0,0 @@ | ||||
| # textdomain: mesecons_movestones | ||||
|  | ||||
| ### init.lua ### | ||||
| Movestone= | ||||
| Sticky Movestone= | ||||
| Vertical Movestone= | ||||
| Vertical Sticky Movestone= | ||||
| @@ -53,16 +53,11 @@ end | ||||
|  | ||||
| -- tests if the node can be pushed into, e.g. air, water, grass | ||||
| local function node_replaceable(name) | ||||
| 	local nodedef = minetest.registered_nodes[name] | ||||
|  | ||||
| 	-- everything that can be an mvps stopper (unknown nodes and nodes in the | ||||
| 	-- mvps_stoppers table) must not be replacable | ||||
| 	-- Note: ignore (a stopper) is buildable_to, but we do not want to push into it | ||||
| 	if not nodedef or mesecon.mvps_stoppers[name] then | ||||
| 		return false | ||||
| 	if minetest.registered_nodes[name] then | ||||
| 		return minetest.registered_nodes[name].buildable_to or false | ||||
| 	end | ||||
|  | ||||
| 	return nodedef.buildable_to or false | ||||
| 	return false | ||||
| end | ||||
|  | ||||
| function mesecon.mvps_get_stack(pos, dir, maximum, all_pull_sticky) | ||||
| @@ -81,9 +76,9 @@ function mesecon.mvps_get_stack(pos, dir, maximum, all_pull_sticky) | ||||
| 			if #nodes > maximum then return nil end | ||||
|  | ||||
| 			-- add connected nodes to frontiers | ||||
| 			local nndef = minetest.registered_nodes[nn.name] | ||||
| 			if nndef and nndef.mvps_sticky then | ||||
| 				local connected = nndef.mvps_sticky(np, nn) | ||||
| 			if minetest.registered_nodes[nn.name] | ||||
| 			and minetest.registered_nodes[nn.name].mvps_sticky then | ||||
| 				local connected = minetest.registered_nodes[nn.name].mvps_sticky(np, nn) | ||||
| 				for _, cp in ipairs(connected) do | ||||
| 					frontiers:add(cp) | ||||
| 				end | ||||
| @@ -96,9 +91,10 @@ function mesecon.mvps_get_stack(pos, dir, maximum, all_pull_sticky) | ||||
| 			for _, r in ipairs(mesecon.rules.alldirs) do | ||||
| 				local adjpos = vector.add(np, r) | ||||
| 				local adjnode = minetest.get_node(adjpos) | ||||
| 				local adjdef = minetest.registered_nodes[adjnode.name] | ||||
| 				if adjdef and adjdef.mvps_sticky then | ||||
| 					local sticksto = adjdef.mvps_sticky(adjpos, adjnode) | ||||
| 				if minetest.registered_nodes[adjnode.name] | ||||
| 				and minetest.registered_nodes[adjnode.name].mvps_sticky then | ||||
| 					local sticksto = minetest.registered_nodes[adjnode.name] | ||||
| 						.mvps_sticky(adjpos, adjnode) | ||||
|  | ||||
| 					-- connects to this position? | ||||
| 					for _, link in ipairs(sticksto) do | ||||
|   | ||||
| @@ -1 +0,0 @@ | ||||
| fixture_paths = {"../.test_fixtures"} | ||||
| @@ -1,297 +0,0 @@ | ||||
| require("mineunit") | ||||
|  | ||||
| fixture("mesecons_mvps") | ||||
|  | ||||
| world.set_default_node("air") | ||||
|  | ||||
| describe("node movement", function() | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	it("works with no moved nodes", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
|  | ||||
| 		assert.same({true, {}, {}}, {mesecon.mvps_push(pos, dir, 1, "")}) | ||||
| 		assert.same({true, {}, {}}, {mesecon.mvps_pull_all(pos, dir, 1, "")}) | ||||
| 		assert.same({true, {}, {}}, {mesecon.mvps_pull_single(pos, dir, 1, "")}) | ||||
| 	end) | ||||
|  | ||||
| 	it("works with simple stack", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
| 		world.set_node(vector.add(pos, dir), "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_push(pos, dir, 2, ""))) | ||||
| 		assert.equal("air", world.get_node(pos).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, vector.multiply(dir, 2))).name) | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_pull_all(vector.add(pos, dir), vector.multiply(dir, -1), 2, ""))) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(pos).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name) | ||||
| 		assert.equal("air", world.get_node(vector.add(pos, vector.multiply(dir, 2))).name) | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_pull_single(pos, vector.multiply(dir, -1), 1, ""))) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.subtract(pos, dir)).name) | ||||
| 		assert.equal("air", world.get_node(pos).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("works with sticky nodes", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 0, y = 1, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
| 		world.set_node(vector.offset(pos, 0, 1, 0), "mesecons_mvps:test_sticky") | ||||
| 		world.set_node(vector.offset(pos, 1, 1, 0), "mesecons:test_conductor_off") | ||||
| 		world.set_node(vector.offset(pos, 1, 2, 0), "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_push(pos, dir, 4, ""))) | ||||
| 		assert.equal("air", world.get_node(vector.offset(pos, 1, 1, 0)).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 2, 0)).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 3, 0)).name) | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_pull_all(vector.add(pos, dir), vector.multiply(dir, -1), 4, ""))) | ||||
| 		assert.equal("air", world.get_node(vector.offset(pos, 1, 0, 0)).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 1, 0)).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 2, 0)).name) | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_pull_single(pos, vector.multiply(dir, -1), 3, ""))) | ||||
| 		assert.equal("air", world.get_node(vector.offset(pos, 1, -1, 0)).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 0, 0)).name) | ||||
| 		assert.equal("air", world.get_node(vector.offset(pos, 1, 1, 0)).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("respects maximum", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
| 		world.set_node(vector.add(pos, dir), "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.is_true(not mesecon.mvps_push(pos, dir, 1, "")) | ||||
| 	end) | ||||
|  | ||||
| 	it("is blocked by basic stopper", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons_mvps:test_stopper") | ||||
|  | ||||
| 		assert.is_true(not mesecon.mvps_push(pos, dir, 1, "")) | ||||
| 	end) | ||||
|  | ||||
| 	it("is blocked by conditional stopper", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
|  | ||||
| 		world.set_node(pos, {name = "mesecons_mvps:test_stopper_cond", param2 = 0}) | ||||
| 		assert.is_true(not mesecon.mvps_push(pos, dir, 1, "")) | ||||
|  | ||||
| 		world.set_node(pos, {name = "mesecons_mvps:test_stopper_cond", param2 = 1}) | ||||
| 		assert.is_true((mesecon.mvps_push(pos, dir, 1, ""))) | ||||
| 	end) | ||||
|  | ||||
| 	-- TODO: I think this is supposed to work? | ||||
| 	pending("is blocked by ignore", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
| 		world.set_node(vector.add(pos, dir), "ignore") | ||||
|  | ||||
| 		assert.is_true(not mesecon.mvps_push(pos, dir, 1, "")) | ||||
| 	end) | ||||
|  | ||||
| 	it("moves metadata", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
| 		minetest.get_meta(pos):set_string("foo", "bar") | ||||
| 		minetest.get_node_timer(pos):set(12, 34) | ||||
|  | ||||
| 		mesecon.mvps_push(pos, dir, 1, "") | ||||
| 		assert.equal("bar", minetest.get_meta(vector.add(pos, dir)):get("foo")) | ||||
| 		local moved_timer = minetest.get_node_timer(vector.add(pos, dir)) | ||||
| 		assert.equal(12, moved_timer:get_timeout()) | ||||
| 		assert.equal(34, moved_timer:get_elapsed()) | ||||
| 		moved_timer:stop() | ||||
| 		assert.same({}, minetest.get_meta(pos):to_table().fields) | ||||
| 		assert.is_false(minetest.get_node_timer(pos):is_started()) | ||||
| 	end) | ||||
|  | ||||
| 	it("calls move callbacks", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		world.set_node(pos, {name = "mesecons_mvps:test_on_move", param2 = 123}) | ||||
| 		minetest.get_meta(pos):set_string("foo", "bar") | ||||
| 		local move_info = {vector.add(pos, dir), world.get_node(pos), pos, minetest.get_meta(pos):to_table()} | ||||
|  | ||||
| 		mesecon.mvps_push(pos, dir, 1, "") | ||||
| 		assert.equal(1, #mesecon._test_moves) | ||||
| 		assert.same(move_info, mesecon._test_moves[1]) | ||||
| 	end) | ||||
|  | ||||
| 	it("executes autoconnect hooks", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
|  | ||||
| 		mesecon.mvps_push(pos, dir, 1, "") | ||||
| 		mineunit:execute_globalstep() -- Execute delayed autoconnect hook | ||||
| 		assert.equal(2, #mesecon._test_autoconnects) | ||||
| 	end) | ||||
|  | ||||
| 	it("updates moved receptors", function() | ||||
| 		local pos1 = {x = 0, y = 0, z = 0} | ||||
| 		local pos2 = vector.offset(pos1, 0, 1, 0) | ||||
| 		local pos3 = vector.offset(pos1, 2, 0, 0) | ||||
| 		local pos4 = vector.offset(pos1, 0, 0, 1) | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		mesecon._test_place(pos1, "mesecons:test_receptor_on") | ||||
| 		mesecon._test_place(pos2, "mesecons:test_conductor_off") | ||||
| 		mesecon._test_place(pos3, "mesecons:test_conductor_off") | ||||
| 		mesecon._test_place(pos4, "mesecons:test_conductor_off") | ||||
| 		mesecon._test_place(vector.add(pos4, dir), "mesecons:test_conductor_off") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
|  | ||||
| 		mesecon.mvps_push(pos1, dir, 1, "") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(pos2).name) | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(pos3).name) | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(pos4).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("updates moved conductors", function() | ||||
| 		local pos1 = {x = 0, y = 0, z = 0} | ||||
| 		local pos2 = vector.offset(pos1, 0, 1, 0) | ||||
| 		local pos3 = vector.offset(pos1, 0, -1, 0) | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		mesecon._test_place(pos1, "mesecons:test_conductor_off") | ||||
| 		mesecon._test_place(pos2, "mesecons:test_receptor_on") | ||||
| 		mesecon._test_place(pos3, "mesecons:test_conductor_off") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
|  | ||||
| 		mesecon.mvps_push(pos1, dir, 1, "") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_off action | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos1, dir)).name) | ||||
| 		assert.equal("mesecons:test_conductor_off", world.get_node(pos3).name) | ||||
|  | ||||
| 		mesecon.mvps_pull_all(vector.add(pos1, dir), vector.multiply(dir, -1), 1, "") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(pos1).name) | ||||
| 		assert.equal("mesecons:test_conductor_on", world.get_node(pos3).name) | ||||
| 	end) | ||||
|  | ||||
| 	it("updates moved effectors", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		mesecon._test_place(pos, "mesecons:test_effector") | ||||
| 		mesecon._test_place(vector.offset(pos, 0, 1, 0), "mesecons:test_receptor_on") | ||||
| 		mesecon._test_place(vector.add(pos, dir), "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
|  | ||||
| 		mesecon.mvps_push(pos, dir, 2, "") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/deactivate/change actions | ||||
| 		assert.equal(tonumber("10000001", 2), world.get_node(vector.add(pos, dir)).param2) | ||||
|  | ||||
| 		mineunit:execute_globalstep() -- Let the component cool down | ||||
|  | ||||
| 		mesecon.mvps_pull_single(vector.add(pos, dir), vector.multiply(dir, -1), 1, "") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/deactivate/change actions | ||||
| 		assert.equal(tonumber("10000100", 2), world.get_node(pos).param2) | ||||
| 	end) | ||||
|  | ||||
| 	-- Since turnon is called before turnoff when pushing, effectors may be incorrectly turned off. | ||||
| 	it("does not overwrite turnon with receptor_off", function() | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		local dir = {x = 1, y = 0, z = 0} | ||||
| 		mesecon._test_place(pos, "mesecons:test_effector") | ||||
| 		mesecon._test_place(vector.add(pos, dir), "mesecons:test_conductor_off") | ||||
| 		mesecon._test_place(vector.add(pos, vector.multiply(dir, 2)), "mesecons:test_receptor_on") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on action | ||||
| 		mineunit:execute_globalstep() -- Execute activate/change actions | ||||
|  | ||||
| 		mesecon.mvps_push(pos, dir, 3, "") | ||||
| 		mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions | ||||
| 		mineunit:execute_globalstep() -- Execute activate/deactivate/change actions | ||||
| 		assert.equal(tonumber("10000001", 2), world.get_node(vector.add(pos, dir)).param2) | ||||
| 	end) | ||||
|  | ||||
| 	-- mineunit doesn't yet implement minetest.check_for_falling. | ||||
| 	pending("causes nodes to fall", function() | ||||
| 	end) | ||||
| end) | ||||
|  | ||||
| describe("protection", function() | ||||
| 	teardown(function() | ||||
| 		minetest.settings:remove("mesecon.mvps_protection_mode") | ||||
| 	end) | ||||
|  | ||||
| 	after_each(function() | ||||
| 		mesecon._test_reset() | ||||
| 		world.clear() | ||||
| 	end) | ||||
|  | ||||
| 	local protected_pos = {x = 1, y = 0, z = 0} | ||||
| 	mineunit:protect(protected_pos, "Joe") | ||||
|  | ||||
| 	it("blocks movement", function() | ||||
| 		minetest.settings:set("mesecon.mvps_protection_mode", "restrict") | ||||
|  | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Bob")}) | ||||
| 	end) | ||||
|  | ||||
| 	it("allows owner's movement", function() | ||||
| 		minetest.settings:set("mesecon.mvps_protection_mode", "restrict") | ||||
|  | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Joe"))) | ||||
| 	end) | ||||
|  | ||||
| 	it("'ignore'", function() | ||||
| 		minetest.settings:set("mesecon.mvps_protection_mode", "ignore") | ||||
|  | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Bob"))) | ||||
| 	end) | ||||
|  | ||||
| 	it("'normal'", function() | ||||
| 		minetest.settings:set("mesecon.mvps_protection_mode", "normal") | ||||
|  | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "")}) | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_push(pos, {x = 0, y = 1, z = 0}, 1, ""))) | ||||
| 	end) | ||||
|  | ||||
| 	it("'compat'", function() | ||||
| 		minetest.settings:set("mesecon.mvps_protection_mode", "compat") | ||||
|  | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, ""))) | ||||
| 	end) | ||||
|  | ||||
| 	it("'restrict'", function() | ||||
| 		minetest.settings:set("mesecon.mvps_protection_mode", "restrict") | ||||
|  | ||||
| 		local pos = {x = 0, y = 0, z = 0} | ||||
| 		world.set_node(pos, "mesecons:test_conductor_off") | ||||
|  | ||||
| 		assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 0, y = 1, z = 0}, 1, "")}) | ||||
| 	end) | ||||
| end) | ||||
| @@ -1,3 +0,0 @@ | ||||
| -- mineunit doesn't yet implement minetest.get_objects_inside_radius | ||||
| pending("object movement", function() | ||||
| end) | ||||
| @@ -1,15 +0,0 @@ | ||||
| Credits of sound files: | ||||
|  | ||||
| Note: Most sounds have not been used verbatim, but tweaked a little to be more suitable for the noteblock mod. | ||||
|  | ||||
| * mesecons_noteblock_litecrash.ogg | ||||
| 	* License: CC BY 3.0 | ||||
| 	* by freesound.org user ani_music | ||||
| 	* Source: https://freesound.org/people/ani_music/sounds/219612/ | ||||
|  | ||||
| Everything else: | ||||
| Created by Mesecons authors, licensed CC BY 3.0. | ||||
|  | ||||
| -------------------- | ||||
| License links: | ||||
| * CC BY 3.0: http://creativecommons.org/licenses/by/3.0/ | ||||
| @@ -6,8 +6,8 @@ This effector makes a sound if powered and can be used for making music. Normall | ||||
| <tr><td>Chest or Locked Chest</td><td>Snare</td></tr> | ||||
| <tr><td>Any tree</td><td>Crash</td></tr> | ||||
| <tr><td>Any wooden planks</td><td>Lite Crash</td></tr> | ||||
| <tr><td>Coal Block</td><td>Explosion sound (fixed pitch)</td></tr> | ||||
| <tr><td>Lava Source</td><td>Fire sound (fixed pitch)</td></tr> | ||||
| <tr><td>Coal Block</td><td>Explosion sound</td></tr> | ||||
| <tr><td>Lava Source</td><td>Fire sound</td></tr> | ||||
| <tr><td>Steel Block</td><td>Piano (high pitch, one octave higher than normal)</td></tr> | ||||
| <tr><td>Any other block</td><td>Piano (low pitch)</td></tr> | ||||
| </table> | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| local S = minetest.get_translator(minetest.get_current_modname()) | ||||
|  | ||||
| minetest.register_node("mesecons_noteblock:noteblock", { | ||||
| 	description = S("Noteblock"), | ||||
| 	description = "Noteblock", | ||||
| 	tiles = {"mesecons_noteblock.png"}, | ||||
| 	is_ground_content = false, | ||||
| 	groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}, | ||||
| @@ -20,7 +18,6 @@ minetest.register_node("mesecons_noteblock:noteblock", { | ||||
| 			mesecon.noteblock_play(pos, node.param2) | ||||
| 		end | ||||
| 	}}, | ||||
| 	place_param2 = 11, -- initialize at C note | ||||
| 	on_blast = mesecon.on_blastnode, | ||||
| }) | ||||
|  | ||||
| @@ -46,7 +43,7 @@ local soundnames = { | ||||
| 	"mesecons_noteblock_a", | ||||
| 	"mesecons_noteblock_asharp", | ||||
| 	"mesecons_noteblock_b", | ||||
| 	"mesecons_noteblock_c" -- << noteblock is initialized here | ||||
| 	"mesecons_noteblock_c" | ||||
| } | ||||
|  | ||||
| local node_sounds = {} | ||||
| @@ -75,9 +72,6 @@ mesecon.noteblock_play = function(pos, param2) | ||||
| 	pos.y = pos.y-1 | ||||
| 	local nodeunder = minetest.get_node(pos).name | ||||
| 	local soundname = node_sounds[nodeunder] | ||||
| 	local use_pitch = true | ||||
| 	local pitch | ||||
| 	-- Special sounds | ||||
| 	if not soundname then | ||||
| 		for k,v in pairs(node_sounds_group) do | ||||
| 			local g = minetest.get_item_group(nodeunder, k) | ||||
| @@ -87,7 +81,6 @@ mesecon.noteblock_play = function(pos, param2) | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	-- Piano | ||||
| 	if not soundname then | ||||
| 		soundname = soundnames[param2] | ||||
| 		if not soundname then | ||||
| @@ -97,17 +90,6 @@ mesecon.noteblock_play = function(pos, param2) | ||||
| 		if nodeunder == steelblock_nodename then | ||||
| 			soundname = soundname.. 2 | ||||
| 		end | ||||
| 		use_pitch = false | ||||
| 	end | ||||
| 	-- Disable pitch for fire and explode because they'd sound too odd | ||||
| 	if soundname == "fire_fire" or soundname == "tnt_explode" then | ||||
| 		use_pitch = false | ||||
| 	end | ||||
| 	if use_pitch then | ||||
| 		-- Calculate pitch | ||||
| 		-- Adding 1 to param2 because param2=11 is *lowest* pitch sound | ||||
| 		local val = (param2+1)%12 | ||||
| 		pitch = 2^((val-6)/12) | ||||
| 	end | ||||
| 	pos.y = pos.y+1 | ||||
| 	if soundname == "fire_fire" then | ||||
| @@ -115,6 +97,6 @@ mesecon.noteblock_play = function(pos, param2) | ||||
| 		local handle = minetest.sound_play(soundname, {pos = pos, loop = true}) | ||||
| 		minetest.after(3.0, minetest.sound_fade, handle, -1.5, 0.0) | ||||
| 	else | ||||
| 		minetest.sound_play(soundname, {pos = pos, pitch = pitch}, true) | ||||
| 		minetest.sound_play(soundname, {pos = pos}, true) | ||||
| 	end | ||||
| end | ||||
|   | ||||
| @@ -1,2 +0,0 @@ | ||||
| # textdomain: mesecons_noteblock | ||||
| Noteblock=Notenblock | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user