-- CONTENTS
-- Formspecs and functions for the consoles
-- Node Definitions (line ~470)
-- Go to recipes.lua for crafting these
-- At the bottom, Tardis Monitor

-- The definitions and formspecs can't be separated because they are local functions

local S = minetest.get_translator("drwho_tardis")
local data = minetest.get_mod_storage()

--formspecs


-- Travel Factor, X, Y, Z
local function get_formspec_fxyz(set) 
	local id = set.id -- TARDIS ID Code, passed to formspec every time
	local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))-- Get current tardis position
	local factor = data:get_int(id.."factor") -- Get current Travel Factor Value
	
	-- local var = <changed_value> or <current_value>
	-- <changed_value> is given to the formspec when buttons are pressed, reloading it with new value
	local fac  = set.fac or factor
	local addx = set.addx or data:get_int(id.."x_dest")
	local addy = set.addy or data:get_int(id.."y_dest")
	local addz = set.addz or data:get_int(id.."z_dest")
	local outx = set.outx or out_pos.x 
	local outy = set.outy or out_pos.y
	local outz = set.outz or out_pos.z

	local tfactor = S("Travel Factor: @1", fac) -- Travel Factor: 6
	local dest = S("Destination:         @1,    @2,    @3", addx, addy, addz)
	local cur =  S("Current Position:         @1,    @2,    @3", outx, outy, outz)
    return "size[10,10]"..
		"label[1,1.25;"..minetest.formspec_escape(tfactor).."]".. -- Travel Factor:
		"image_button[4,1;1,1;switch_1.png;one; ;false;false;switch_2.png]"..
		"image_button[5.2,1;1,1;switch_1.png;ten; ;false;false;switch_2.png]"..
		"image_button[6.4,1;1,1;switch_1.png;hundred; ;false;false;switch_2.png]"..
		"image_button[7.6,1;1,1;switch_1.png;thousand; ;false;false;switch_2.png]"..
		"tooltip[one;1]"..
		"tooltip[ten;10]".. -- Travel Factor tooltips
		"tooltip[hundred;100]"..
		"tooltip[thousand;1000]"..

		"label[1,3;"..minetest.formspec_escape(cur).."]"..  -- Current Position:  X,   Y,   Z
		"label[1,5;"..minetest.formspec_escape(dest).."]".. -- Destination:   X,   Y,   Z
		
		"image_button[0.5,7;2,2;handle_1.png;xposup; ;false;false;handle_2.png]".. -- Change X POS
		"image_button[1.5,7;2,2;handle_1.png;xposdown; ;false;false;handle_2.png]"..

		"image_button[3.5,7;2,2;handle_1.png;yposup; ;false;false;handle_2.png]"..  -- Change Y POS
		"image_button[4.5,7;2,2;handle_1.png;yposdown; ;false;false;handle_2.png]"..

		"image_button[6.5,7;2,2;handle_1.png;zposup; ;false;false;handle_2.png]".. -- Change Z POS
		"image_button[7.5,7;2,2;handle_1.png;zposdown; ;false;false;handle_2.png]".. 

		"tooltip[xposup;Increase X Pos]"..
		"tooltip[xposdown;Decrease X Pos]"..
		"tooltip[yposup;Increase Y Pos]"..
		"tooltip[yposdown;Decrease Y Pos]"..
		"tooltip[zposup;Increase Z Pos]"..
		"tooltip[zposdown;Decrease Z Pos]"
end
local function get_formspec_w() -- GO Lever
    return "size[10,10]"..
		--"button[1,3;5,1;go;Go]"
		"image_button_exit[3,3;4,4;lever_1.png;go; ;false;false;lever_2.png]"
end
local function get_formspec_r(set) -- Power Left (Time Rotor)
	local max_power = tonumber(minetest.settings:get("drwho_tardis.max_power")) or 10
	local power = S("Power Left: @1 out of @2", set, max_power)
	local info = S("1 power is generated every 15 seconds.")
    return "size[10,10]"..
		"label[1,1;"..minetest.formspec_escape(power).."]"..
		"label[1,2;"..minetest.formspec_escape(info).."]"
end
local function get_formspec_fb(set) 
	local id = set.id -- TARDIS ID Code, passed to formspec every time
	local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))-- Get current tardis position
	local success, biomes = findbiome.list_biomes()
	local sid = biomes[sid] and sid or 1

	-- local var = <changed_value> or <current_value>
	-- <changed_value> is given to the formspec when buttons are pressed, reloading it with new value
	local addx = set.addx or data:get_int(id.."x_dest")
	local addy = set.addy or data:get_int(id.."y_dest")
	local addz = set.addz or data:get_int(id.."z_dest")
	local outx = out_pos.x 
	local outy = out_pos.y
	local outz = out_pos.z
	local biome_pos = set.biome_pos or {x=0,y=0,z=0}
	local biomex = set.biomex or biome_pos.x or 0
	local biomey = set.biomey or biome_pos.y or 0
	local biomez = set.biomez or biome_pos.z or 0

	local dest = S("Destination:  @1,  @2,  @3", addx, addy, addz)
	local cur =  S("Current Position:  @1,  @2,  @3", outx, outy, outz)
	local loc = S("Find a biome")
	local list = S("List of all biomes:")
	local textf = S("Type the biome name here:")
	local bpos = S("Biome Position:  @1, @2, @3", biomex, biomey, biomez) or ""
	local note = set.note or ""
	local fbiome_tt = S("Find Biome (press this first, after entering biome name)")
	local set_tt = S("Set Found Biome Position as Destination")

	-- Create sidebar with buttons part
	local biome = biomes[sid]
	local sidebuttons = "label[0,0;"..minetest.formspec_escape(loc).."]".. 
						"label[0,1;"..minetest.formspec_escape(cur).."]"..  
						"label[0,1.5;"..minetest.formspec_escape(dest).."]"..
						"label[0,2;"..minetest.formspec_escape(bpos).."]"..
						"label[0.5,2.75;"..minetest.formspec_escape(note).."]"
	
	-- Write in the biome name field
	sidebuttons = sidebuttons.."field[0.25,4.5;4,1;setbiome;"..textf..";biome]"
	-- Find biome button
	sidebuttons = sidebuttons.."image_button[0.5,6;2,2;handle_1.png;fbiome; ;false;false;handle_2.png]"..
								"tooltip[fbiome;"..minetest.formspec_escape(fbiome_tt).."]"
	-- Set biome as destination button
	sidebuttons = sidebuttons.."image_button[2,6;2,2;handle_1.png;set; ;false;false;handle_2.png]"..
								"tooltip[set;"..minetest.formspec_escape(set_tt).."]"
    -- Create biome list formspec part
	local biomeslistformspec = "label[6,0.5;"..minetest.formspec_escape(list).."]"..
								"textlist[5,1;5,9;consolefindbiome;"

	local first = true
	for b=1, #biomes do
		if not first then
			biomeslistformspec = biomeslistformspec .. ","
		end
		first = false
		biomeslistformspec = biomeslistformspec .. minetest.formspec_escape(biomes[b])
	end
	biomeslistformspec = biomeslistformspec .. ";]"

    return "size[10,10]"..

		sidebuttons..
		biomeslistformspec

end
local function get_formspec_s() -- Extra Functions
	local sonic_tt = S("Create Sonic Screwdriver")
	local heal_tt = S("Heal Me")
	local axe_tt = S("Create an Axe")
	local scan_tt = S("Scan Named Player")
	local submit_tt = S("Locate Named Player")
	local food_tt = S("Create a Biscuit")
	local antigrav_tt = S("Toggle Antigrav")
	local attack_tt = S("Activate Weapons")
	local pick_tt = S("Create a Pickaxe")
	local locate_fieldtext = S("type name here... ")
    return "size[10,10]"..
		"field[1,9;8,1;locate;;"..minetest.formspec_escape(locate_fieldtext).."]"..
		"image_button[1,1;2,2;switch_1.png;pick; ;false;false;switch_2.png]"..
		"image_button[2.5,1;2,2;switch_1.png;heal; ;false;false;switch_2.png]"..
		"image_button[4,1;2,2;switch_1.png;axe; ;false;false;switch_2.png]"..
		"image_button[1,3;2,2;switch_1.png;antigrav; ;false;false;switch_2.png]"..
		"image_button[2.5,3;2,2;switch_1.png;food; ;false;false;switch_2.png]"..
		"image_button[4,3;2,2;switch_1.png;attack; ;false;false;switch_2.png]"..
		"image_button[6,1;4,4;handle_1.png;sonic; ;false;false;handle_2.png]"..
		"image_button_exit[0.5,5.5;3,3;dial_1.png;submit; ;false;false;dial_2.png]"..
		"image_button[3.5,5.5;3,3;dial_1.png;scan; ;false;false;dial_2.png]"..
		"tooltip[sonic;"..minetest.formspec_escape(sonic_tt).."]"..
		"tooltip[heal;"..minetest.formspec_escape(heal_tt).."]"..
		"tooltip[axe;"..minetest.formspec_escape(axe_tt).."]"..
		"tooltip[scan;"..minetest.formspec_escape(scan_tt).."]"..
		"tooltip[submit;"..minetest.formspec_escape(submit_tt).."]"..
		"tooltip[food;"..minetest.formspec_escape(food_tt).."]"..
		"tooltip[antigrav;"..minetest.formspec_escape(antigrav_tt).."]"..
		"tooltip[attack;"..minetest.formspec_escape(attack_tt).."]"..
		"tooltip[pick;"..minetest.formspec_escape(pick_tt).."]"
end

-- set should be the `name` e.g. 'green'
local function get_formspec_ext(set) -- Change Exterior 
	local ext_list = minetest.deserialize(data:get_string("ext_list"))
	local ext_text = S("Change Exterior Shell")
	local index = 1
	local ext_name_table = {}
	for i, ext in ipairs(ext_list) do
		if not ext then break end
		ext_name_table[#ext_name_table+1] = ext.name
		if ext.name == set then index = i end -- get the index of the current ext so it is already selected
	end
	local formspec = "size[10,10]"..
			"label[1,1;"..minetest.formspec_escape(ext_text).."]"..
			'dropdown[1,2;4,8;ext_dropdown;'..table.concat(ext_name_table, ',')..';'..index..']'..
			"button_exit[7,7;2,1;close;Close]"..
			"item_image[6,2;3,3;"..minetest.formspec_escape("drwho_tardis:tardis_"..set).."]"
	return formspec
end

local function get_formspec_o(set) -- Waypoints
	local id = set.id -- TARDIS ID number is given to formspec function
	local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))-- Get current tardis position
	local way1 = set.way1 or minetest.deserialize(data:get_string(id.."way1"))
	local way2 = set.way2 or minetest.deserialize(data:get_string(id.."way2"))
	local way3 = set.way3 or minetest.deserialize(data:get_string(id.."way3"))
	local x_dest = set.x_dest or data:get_int(id.."x_dest")
	local y_dest = set.y_dest or data:get_int(id.."y_dest")
	local z_dest = set.z_dest or data:get_int(id.."z_dest")

	local cur = S("Current Position:  @1,  @2,  @3", out_pos.x, out_pos.y, out_pos.z)
	local dest = S("Destination:  @1,  @2,  @3", x_dest, y_dest, z_dest)
	local way_one = S("Waypoint One:  @1,  @2,  @3", way1.x, way1.y, way1.z)
	local way_two = S("Waypoint Two:  @1,  @2,  @3", way2.x, way2.y, way2.z)
	local way_three = S("Waypoint Three:  @1,  @2,  @3", way3.x, way3.y, way3.z)
	local set_way = S("Use Waypoint as Destination?")

	local set_one_tt = S("Set Waypoint 1 to Current Position")
	local set_two_tt = S("Set Waypoint 2 to Current Position")
	local set_three_tt = S("Set Waypoint 3 to Current Position")
	local use_one_tt = S("Use Waypoint 1")
	local use_two_tt = S("Use Waypoint 2")
	local use_three_tt = S("Use Waypoint 3")

    return "size[10,10]"..
		"label[4,1;"..minetest.formspec_escape(cur).."]"..  -- Current Position:  X,   Y,   Z
		"label[4,1.5;"..minetest.formspec_escape(dest).."]"..  -- Destination:  X,   Y,   Z
		"label[4,3.5;"..minetest.formspec_escape(way_one).."]"..  -- Waypoint One:     X,   Y,   Z
		"label[4,4;"..minetest.formspec_escape(way_two).."]"..    -- Waypoint Two:     X,   Y,   Z
		"label[4,4.5;"..minetest.formspec_escape(way_three).."]"..-- Waypoint Three:   X,   Y,   Z

		"image_button[1,1;2,2;dial_1.png;set_one; ;false;false;dial_2.png]"..
		"image_button[1,4;2,2;dial_1.png;set_two; ;false;false;dial_2.png]"..
		"image_button[1,7;2,2;dial_1.png;set_three; ;false;false;dial_2.png]"..

		"label[5,6.5;"..minetest.formspec_escape(set_way).."]".. -- Use Waypoint as Destination?
		"image_button[4.5,7;2,2;switch_1.png;use_one; ;false;false;switch_2.png]"..
		"image_button[6,7;2,2;switch_1.png;use_two; ;false;false;switch_2.png]"..
		"image_button[7.5,7;2,2;switch_1.png;use_three; ;false;false;switch_2.png]"..

		"tooltip[set_one;"..minetest.formspec_escape(set_one_tt).."]"..
		"tooltip[set_two;"..minetest.formspec_escape(set_two_tt).."]"..
		"tooltip[set_three;"..minetest.formspec_escape(set_three_tt).."]"..
		"tooltip[use_one;"..minetest.formspec_escape(use_one_tt).."]"..
		"tooltip[use_two;"..minetest.formspec_escape(use_two_tt).."]"..
		"tooltip[use_three;"..minetest.formspec_escape(use_three_tt).."]"
end
local function general_functions(pos, formname, fields, sender)
	local meta = minetest.get_meta(pos)
	local id = meta:get_string("id")
	local name = sender:get_player_name()
	local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
	local factor = data:get_int(id.."factor")
	local inv = sender:get_inventory()
	if fields.xposup then -- Increase X Position
		meta:set_string("formspec", get_formspec_fxyz({
			addx = data:get_int(id.."x_dest")+factor, 
			outx = out_pos.x, 
			id = id
		}))
		data:set_int(id.."x_dest", data:get_int(id.."x_dest")+factor)
	elseif fields.xposdown then -- Decrease X Position
		meta:set_string("formspec", get_formspec_fxyz({
			addx = data:get_int(id.."x_dest")-factor, 
			outx = out_pos.x, 
			id = id
		}))
		data:set_int(id.."x_dest", data:get_int(id.."x_dest")-factor)
	elseif fields.yposup then-- Increase Y Position
		meta:set_string("formspec", get_formspec_fxyz({
			addy = data:get_int(id.."y_dest")+factor, 
			outy = out_pos.y, 
			id = id
		}))
		data:set_int(id.."y_dest", data:get_int(id.."y_dest")+factor)
	elseif fields.yposdown then -- Decrease Y Position
		meta:set_string("formspec", get_formspec_fxyz({
			addy = data:get_int(id.."y_dest")-factor, 
			outy = out_pos.y, 
			id = id
		}))
		data:set_int(id.."y_dest", data:get_int(id.."y_dest")-factor)
	elseif fields.zposup then -- Increase Z Position
		meta:set_string("formspec", get_formspec_fxyz({
			addz = data:get_int(id.."z_dest")+factor, 
			outz = out_pos.z, 
			id = id
		}))
		data:set_int(id.."z_dest", data:get_int(id.."z_dest")+factor)
	elseif fields.zposdown then -- Decrease Z Position
		meta:set_string("formspec", get_formspec_fxyz({
			addz = data:get_int(id.."z_dest")-factor, 
			outz = out_pos.z, 
			id = id
		}))
		data:set_int(id.."z_dest", data:get_int(id.."z_dest")-factor)
	elseif fields.one then -- set Travel Factor to 1
		meta:set_string("formspec", get_formspec_fxyz({fac = 1, id = id}))
		data:set_int(id.."factor", 1)
	elseif fields.ten then -- set Travel Factor to 10
		meta:set_string("formspec", get_formspec_fxyz({fac = 10, id = id}))
		data:set_int(id.."factor", 10)
	elseif fields.hundred then -- set Travel Factor to 100
		meta:set_string("formspec", get_formspec_fxyz({fac = 100, id = id}))
		data:set_int(id.."factor", 100)
	elseif fields.thousand then -- set Travel Factor to 1000
		meta:set_string("formspec", get_formspec_fxyz({fac = 1000, id = id}))
		data:set_int(id.."factor", 1000)

	--extra functions
	elseif fields.submit then -- Locate a player
		if data:get_int(id.."power") < 2 then minetest.chat_send_player(name, S("You Need 2 Power")) else
			local victim = minetest.get_player_by_name(fields.locate)
			if not victim then minetest.chat_send_player(name, fields.locate .. S(" not found")) else 
				local vpos = victim:get_pos()
				data:set_int(id.."x_dest", vpos.x) 
				data:set_int(id.."y_dest", vpos.y+1)
				data:set_int(id.."z_dest", vpos.z)
				minetest.chat_send_player(name, S("Player Located"))
				data:set_int(id.."power", data:get_string(id.."power")-2)
			end
		end
	elseif fields.sonic then -- Create a sonic screwdriver
		if data:get_int(id.."power") < 5 then minetest.chat_send_player(name, S("You Need 5 Power")) else
			pos.y = pos.y+1
			local sonictypes = 4 --number of variants for end, middle, and top
			local top = math.random(1,sonictypes)
			local mid = math.random(1,sonictypes)
			local bottom = math.random(1,sonictypes)
			sonicname = "drwho_tardis:sonic_screwdriver_"..top.."_"..mid.."_"..bottom
			--[[ -- Full function that is not needed here anymore
			drwho_tardis:register_sonic_device({ -- Creates and registers the new sonic, then returns the itemname to be given to add_item()
				gentype = "choose", 
				sonictype = "screwdriver", -- Specify it is a screwdriver
				customname = sonicname, -- Generated above
				no_creative = false, -- Appear in creative inventory
				top = top,
				mid = mid,
				bottom = bottom,
			})
			--]]
			minetest.add_item(pos, sonicname)
			data:set_int(id.."power", data:get_string(id.."power")-5)
			if minetest.get_modpath("awards") and _drwho_tardis.GAMETYPE=="mtg" then
				awards.unlock(name, "drwho_tardis:get_sonic_screwdriver") -- Unlock award if awards are enabled
			end
		end
	elseif fields.heal then -- Heal the pilot
		if data:get_int(id.."power") < 3 then minetest.chat_send_player(name, S("You Need 3 Power")) else
			sender:set_hp(40)
			data:set_int(id.."power", data:get_string(id.."power")-3)
		end
	elseif fields.scan then -- Scan a player by name
		if data:get_int(id.."power") < 1 then minetest.chat_send_player(name, S("You Need 1 Power")) else
			local victim = minetest.get_player_by_name(fields.locate)
			if not victim then minetest.chat_send_player(name, fields.locate .. S(" not found")) else 
				local item = victim:get_wielded_item()
				local item_name = item:get_name()
				if item:get_name() == "" then item_name = "nothing" end
				minetest.chat_send_player(name, S("@1 is holding @2 and has @3 hearts", fields.locate, item_name, victim:get_hp()/2))
				data:set_int(id.."power", data:get_string(id.."power")-1)
			end
		end
	elseif fields.pick then -- Create a diamond pickaxe
		if data:get_int(id.."power") < 5 then minetest.chat_send_player(name, S("You Need 5 Power")) else
			pos.y = pos.y+1
			minetest.add_item(pos, "default:pick_diamond")
			data:set_int(id.."power", data:get_string(id.."power")-5)
		end
	elseif fields.axe then -- Create a diamond axe
		if data:get_int(id.."power") < 5 then minetest.chat_send_player(name, S("You Need 5 Power")) else
			pos.y = pos.y+1
			minetest.add_item(pos, "default:axe_diamond")
			data:set_int(id.."power", data:get_string(id.."power")-5)
		end
	elseif fields.antigrav then -- Toggle antigrav mavity system
		local success, status = _drwho_tardis.toggle_mavity(name)
		minetest.chat_send_player(name, S(status))
	elseif fields.food then -- Create a tardis biscuit
		if data:get_int(id.."power") < 1 then minetest.chat_send_player(name, S("You Need 1 Power")) else
			pos.y = pos.y+1
			minetest.add_item(pos, "drwho_tardis:biscuit")
			data:set_int(id.."power", data:get_string(id.."power")-1)
		end
	elseif fields.attack then -- Attack a nearby player down to 1 hp
		if data:get_int(id.."power") < 1 then minetest.chat_send_player(name, S("You Need 1 Power")) else
			local objs = minetest.get_objects_inside_radius(out_pos, 20)
			if objs[1] == nil then minetest.chat_send_player(name, S("No players in range of Tardis")) else
				if objs[1]:get_player_name() ~= "" then
					objs[1]:set_hp(1) --Set their HP to 1
					minetest.chat_send_player(name, objs[1]:get_player_name().." was attacked" )
					if minetest.get_modpath("awards") and _drwho_tardis.GAMETYPE=="mtg" then --check if awards are enabled
						awards.unlock(name, "drwho_tardis:tardis_attack") --unlock 'Threat Nullified' award
					end
					data:set_int(id.."power", data:get_string(id.."power")-1) --reduce power by 1
				end			
			end
		end
	end
end



-- Called when the emerge stuff has completely finished
-- Saves the go_pos, unlocks the interior door, sends a status message in chat
function _drwho_tardis.do_after_travel(go_pos, context)
	--minetest.chat_send_all("Function do_after_travel() called...") -- debug
	if minetest.get_node(go_pos).name ~= "air" then 
		go_pos.y = go_pos.y + 1 -- Make the Tardis land properly, not be 1 block in the ground
	end
	local name = context.name
	local meta = context.meta -- we saved this before
	local id = meta:get_string("id")
	local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
	local look = data:get_string(id.."look")
	local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))--
	local rmeta = minetest.get_meta(r_pos)--
	local style = rmeta:get_string("style")--
	-- local pmeta = sender:get_meta() -- deprecated
	local mavity_type = data:get_string(name.."respect_mavity")
	local effect = context.sound_effect


	-- ADJUST FOR MAVITY and AVOID BEING UNDERGROUND
	--if mavity_type == "yes" or mavity_type == "sink" then -- the emerge_callback did it, send chat message
	local old_go_pos = minetest.deserialize(data:get_string(name.."old_go_pos"))
	if old_go_pos == nil then old_go_pos = {x="??", y="??", z="??"} end -- just in case, we don't want error
	--minetest.chat_send_player(name, S("Tardis was going to be travelling to Y-pos @1 but adjusted for mavity and changed it to Y-pos @2", old_go_pos.y, go_pos.y))
	-- end

	if minetest.is_protected(go_pos, name) then 
		minetest.chat_send_player(name, S("You don't have access to this area!"))
		minetest.sound_stop(effect)
		_drwho_tardis.toggle_int_door(name, "unlock") -- Unlock interior door
		_drwho_tardis.switch_time_rotor(name, "off") -- end rotor animation
	else
		-- TODO: add checks for the new area the console rooms are in:
		-- and for MineClone world borders
		--stay away from console room!
		if r_pos.x+100 > go_pos.x and r_pos.x-100 < go_pos.x and r_pos.z+100 > go_pos.z and r_pos.z-100 < go_pos.z and r_pos.y+100 > go_pos.y and r_pos.y-100 < go_pos.y then 
			minetest.chat_send_player(name, "Your Tardis does not want to land at this location") 
			minetest.sound_stop(effect)
			_drwho_tardis.toggle_int_door(name, "unlock") -- Unlock interior door
			_drwho_tardis.switch_time_rotor(name, "off") -- end rotor animation
		else
			if 30900 > go_pos.x and -30900 < go_pos.x and 30900 > go_pos.z and -30900 < go_pos.z and 30900 > go_pos.z and -30900 < go_pos.z then --world limits , update them for MCL as that is different
				minetest.after(8, function(effect)
					minetest.sound_stop(effect)
					_drwho_tardis.toggle_int_door(name, "unlock") -- Unlock interior door
					_drwho_tardis.switch_time_rotor(name, "off") -- end rotor animation
					if minetest.get_modpath("awards") and _drwho_tardis.GAMETYPE == "mtg" then
		
						times_travelled_in_tardis = times_travelled_in_tardis + 1
						minetest.chat_send_player(name, S("Times travelled in TARDIS: @1", times_travelled_in_tardis))
						check_drwho_awards(name) -- Will give times_travelled awards if nessasary
					end
					local ometa = minetest.get_meta(r_pos)
					ometa:set_string("id", id)
					ometa:set_string("formspec", get_formspec_r(data:get_int(id.."power")))
					local otimer = minetest.get_node_timer(r_pos)
					otimer:start(15)
					-- pmeta:set_string("vortex", "no") -- deprecated
					data:set_string(id.."vortex", "no")
					minetest.chat_send_player(name, S("Your Tardis has landed.")) 
				end, effect)
		
				minetest.set_node(out_pos, {name = "air"})
				out_pos = go_pos
				minetest.set_node(out_pos, {name=look})
				
				out_pos.y = out_pos.y+1
				minetest.set_node(out_pos, {name = "air"})
				out_pos.y = out_pos.y-1
				
				local ometa = minetest.get_meta(out_pos)
				ometa:set_string("id", id)
				data:set_string(id.."out_pos", minetest.serialize(out_pos))
				data:set_int(id.."power", data:get_string(id.."power")-1)
				local timer = minetest.get_node_timer(out_pos)
				timer:start(0.2)
				
			else 
				minetest.chat_send_player(name, S("Your Tardis can not travel outside the world!")) 
				minetest.sound_stop(effect)
				_drwho_tardis.toggle_int_door(name, "unlock") -- Unlock interior door
				_drwho_tardis.switch_time_rotor(name, "off") -- end rotor animation
			end
		end
	end
end

-- Emerge callback for loading map areas
function _drwho_tardis.emerge_callback(pos, action, num_calls_remaining, context)
	-- On first call, record number of blocks
	if not context.total_blocks then
		context.total_blocks  = num_calls_remaining + 1
		context.loaded_blocks = 0
	end
	-- Increment number of blocks loaded
	context.loaded_blocks = context.loaded_blocks + 1
	if context.total_blocks == context.loaded_blocks then
		-- Ding! Now we can run our code to float up or down
		--minetest.chat_send_player(context.name, "Finished emerging section") -- debug
		local mavity = data:get_string(context.name .."respect_mavity")
		_drwho_tardis.do_float_fall(context.go_pos, context, mavity) -- Will float fall if mavity settings say so
		-- after that is finished it runs `do_after_travel`
	end
end

-- Function for float falling or coming up from underground
-- Checks the next 100 nodes
-- given the mavity type, which says what type if any adjustments to be made to the Y pos
function _drwho_tardis.do_float_fall(go_pos, context1, mavity)
	local context = { -- reset the context, remove the residual emerge context data so it can run again
		name = context1.name,
		pos1 = context1.pos1,
		pos2 = context1.pos2,
		go_pos = go_pos,
		meta = context1.meta,
		sound_effect = context1.sound_effect,
	}
	--minetest.chat_send_all("Function do_float_fall() called...") -- debug
	if mavity == "yes" then -- float fall
		-- If we are in the air
		if minetest.get_node(go_pos).name == "air" then
			while minetest.get_node(go_pos).name == "air" do
				go_pos.y = go_pos.y - 1 -- Keep moving down until we hit a different node
				if minetest.get_node(go_pos).name == "ignore" then -- Check if we need to
					context.go_pos = go_pos -- save the current go_pos
					-- Load next area
					context.pos1.y = go_pos.y - 1000
					context.pos2.y = go_pos.y + 20
					minetest.emerge_area(context.pos1, context.pos2, _drwho_tardis.emerge_callback, context) -- Load all nodes between pos1 and pos2
					--minetest.chat_send_all("Starting to emerge the next section") -- debug
					return -- end because this function is the callback after emerge is finished
				end
			end
			_drwho_tardis.do_after_travel(go_pos, context)
			return
		else 
		-- It's not air, we are underground or inside nodes
			while minetest.get_node(go_pos).name ~= "air" do
				go_pos.y = go_pos.y + 1 -- Keep moving up until we hit air
				--minetest.chat_send_player(context.name, "Tardis is computing go_pos, the Y level is "..go_pos.y)
				if minetest.get_node(go_pos).name == "ignore" then -- Check if we need to
					context.go_pos = go_pos -- save the current go_pos
					-- Load next area
					context.pos1.y = go_pos.y + 1000
					context.pos2.y = go_pos.y - 20
					minetest.emerge_area(context.pos1, context.pos2, _drwho_tardis.emerge_callback, context) -- Load all nodes between pos1 and pos2
					--minetest.chat_send_all("Starting to emerge the next section")
					return -- end because this function is the callback after emerge is finished
				end
			end
			_drwho_tardis.do_after_travel(go_pos, context)
			return
		end
	elseif mavity == "sink" then -- float fall but also sinks through liquids
		local nodedef = minetest.registered_nodes[minetest.get_node(go_pos).name] -- store def
		--nodedef.liquidtype ~= "none"
		-- If we are in the air or liquid
		if minetest.get_node(go_pos).name == "air" or nodedef.liquidtype ~= "none" then
			while minetest.get_node(go_pos).name == "air" or nodedef.liquidtype ~= "none" do
				go_pos.y = go_pos.y - 1 -- Keep moving down until we hit a different node
				--minetest.chat_send_player(context.name, "Tardis is computing go_pos, the Y level is "..go_pos.y)
				nodedef = minetest.registered_nodes[minetest.get_node(go_pos).name] -- update def for new node
				if minetest.get_node(go_pos).name == "ignore" then -- Check if we need to
					context.go_pos = go_pos -- save the current go_pos
					-- Load next area
					context.pos1.y = go_pos.y - 1000
					context.pos2.y = go_pos.y + 20
					minetest.emerge_area(context.pos1, context.pos2, _drwho_tardis.emerge_callback, context) -- Load all nodes between pos1 and pos2
					--minetest.chat_send_all("Starting to emerge the next section")
					return -- end because this function is the callback after emerge is finished
				end
			end
			_drwho_tardis.do_after_travel(go_pos, context)
			return
		else 
		-- It's not air, we are underground or inside nodes
			while minetest.get_node(go_pos).name ~= "air" or nodedef.liquidtype == "none" do
				go_pos.y = go_pos.y + 1 -- Keep moving up until we hit air
				--minetest.chat_send_player(context.name, "Tardis is computing go_pos, the Y level is "..go_pos.y)
				nodedef = minetest.registered_nodes[minetest.get_node(go_pos).name] -- update def for new node
				if minetest.get_node(go_pos).name == "ignore" then -- Check if we need to
					context.go_pos = go_pos -- save the current go_pos
					-- Load next area
					context.pos1.y = go_pos.y + 1000
					context.pos2.y = go_pos.y - 20
					minetest.emerge_area(context.pos1, context.pos2, _drwho_tardis.emerge_callback, context) -- Load all nodes between pos1 and pos2
					--minetest.chat_send_all("Starting to emerge the next section")
					return -- end because this function is the callback after emerge is finished
				end
			end
			_drwho_tardis.do_after_travel(go_pos, context)
			return
		end
	else -- mavity settings are turned off or not defined
		-- proceed to do_after_travel which finishes up travel stuff
		_drwho_tardis.do_after_travel(go_pos, context)
	end
end


local function travel_to_location(pos, formname, fields, sender)
	local meta = minetest.get_meta(pos)
	local id = meta:get_string("id")
	local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
	local look = data:get_string(id.."look")
	if _drwho_tardis.is_time_rotor(id) then 
		local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
		local rmeta = minetest.get_meta(r_pos)	
		local style = rmeta:get_string("style")
	end
	local go_pos = { x = data:get_int(id.."x_dest"), y = data:get_int(id.."y_dest"), z = data:get_int(id.."z_dest") }
	local pmeta = sender:get_meta()
	local name = sender:get_player_name()
	if fields.go then
		if not _drwho_tardis.is_time_rotor(id) then minetest.chat_send_player(name, S("You need to have a Time Rotor! If you already do, try break it and re-place it.")) else
		if data:get_int(id.."power") == 0 then minetest.chat_send_player(name, S("No Power Left!")) else --power?
			-- LOCK TARDIS DOOR
			_drwho_tardis.toggle_int_door(id, "lock")
			data:set_string(id.."old_go_pos", minetest.serialize(data:get_string(id.."go_pos")))
			-- LOAD AREA
			local pos1change = { x=10, y=100, z=10 } -- load 100 nodes above
			local pos2change = { x=10, y=1000, z=10 } -- and 1000 nodes below
			local pos1 = vector.add(go_pos, pos1change)
			local pos2 = vector.subtract(go_pos, pos2change)
			local context = {-- persist data between callback calls
				name = id, -- Save the name
				go_pos = go_pos, -- Save the go_pos
				pos1 = pos1,
				pos2 = pos2,
				meta = meta, -- I think this is the metadata for warp lever
				sound_effect = minetest.sound_play("tardis_sound", {pos = pos, max_hear_distance = 10}),
			}
			_drwho_tardis.switch_time_rotor(name, "on")
			minetest.chat_send_player(name, S("Your Tardis is dematerialising, and is travelling through the time vortex. The exit door is locked until it lands.")) 
			minetest.emerge_area(pos1, pos2, _drwho_tardis.emerge_callback, context) -- Load all nodes between pos1 and pos2

			-- After the emerge_callback is finished and the Tardis lands somewhere, 
			-- it runs more checks before actually landing there
			-- All that code is in do_after_travel()

		end
	end
	end
end
local function change_look(pos, formname, fields, sender)
	local meta = minetest.get_meta(pos)
	local id = meta:get_string("id")
	if fields.ext_dropdown then
		local selected_option = fields.ext_dropdown
		-- Run code based on the selected option
		data:set_string(id.."look", "drwho_tardis:tardis_"..selected_option)
		meta:set_string("formspec", get_formspec_ext(selected_option)) -- update formspec	
	end
end 

local function find_biome_functions(pos, formname, fields, sender)
	local meta = minetest.get_meta(pos)
	local id = meta:get_string("id")
	local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
	local biome_pos = minetest.deserialize(data:get_string(id.."biome_pos"))

	if fields.set then -- set as destination
		if biome_pos == nil or biome_pos == {x=0,y=0,z=0} then 
			meta:set_string("formspec", get_formspec_fb({
				addx = 0, -- Refresh formspec
				addy = 0,
				addz = 0,
				note = S("Find and set a biome first!"), -- Note shown on formspec 
				id = id}))
		else
			meta:set_string("formspec", get_formspec_fb({
				addx = biome_pos.x, -- Refresh formspec
				addy = biome_pos.y,
				addz = biome_pos.z,
				note = S("Biome position set\nas destination."), -- Note shown on formspec
				id = id}))
			data:set_int(id.."x_dest", biome_pos.x)
			data:set_int(id.."y_dest", biome_pos.y)
			data:set_int(id.."z_dest", biome_pos.z)
		end

	elseif fields.fbiome then
		local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
		local setbiome = fields.setbiome
		minetest.chat_send_all(S("Tardis finding biome: @1", setbiome))
		---[[
		local biome_pos = findbiome.find_biome(out_pos, {setbiome})
		local note = S("Biome found")
		if biome_pos == nil or biome_pos == {x=0,y=0,z=0} then 
			note = S("Something went wrong,\ncheck biome spelling?") -- Note shown on formspec 
		else
			note = S("Biome found!") 
			biome_pos.y = biome_pos.y - 1 --Make the Tardis land on the ground instead of 1 node in the air
		end
		data:set_string(id.."biome_pos", minetest.serialize(biome_pos))
		meta:set_string("formspec", get_formspec_fb({
			biome_pos = biome_pos, -- Refresh formspec
			note = note,
			id = id}))
	end
end
local function waypoint(pos, formname, fields, sender)
	local meta = minetest.get_meta(pos)
	local id = meta:get_string("id")
	local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
	local way1 = minetest.deserialize(data:get_string(id.."way1"))
	local way2 = minetest.deserialize(data:get_string(id.."way2"))
	local way3 = minetest.deserialize(data:get_string(id.."way3"))
	if fields.set_one then
		data:set_string(id.."way1", minetest.serialize(out_pos))
		local way1 = minetest.deserialize(data:get_string(id.."way1"))
		meta:set_string("formspec", get_formspec_o({
			way1 = minetest.deserialize(data:get_string(id.."way1")), -- Refresh formspec
			id = id}))
	elseif fields.use_one  then
		meta:set_string("formspec", get_formspec_o({
			x_dest = way1.x, -- Refresh formspec
			y_dest = way1.y,
			z_dest = way1.z,
			id = id}))
		data:set_int(id.."x_dest", way1.x)
		data:set_int(id.."y_dest", way1.y)
		data:set_int(id.."z_dest", way1.z)
	elseif fields.set_two then
		data:set_string(id.."way2", minetest.serialize(out_pos))
		local way2 = minetest.deserialize(data:get_string(id.."way2"))
		meta:set_string("formspec", get_formspec_o({
			way2 = minetest.deserialize(data:get_string(id.."way2")), -- Refresh formspec
			id = id}))
	elseif fields.use_two then
		meta:set_string("formspec", get_formspec_o({
			x_dest = way2.x, -- Refresh formspec
			y_dest = way2.y,
			z_dest = way2.z,
			id = id}))
		data:set_int(id.."x_dest", way2.x)
		data:set_int(id.."y_dest", way2.y)
		data:set_int(id.."z_dest", way2.z)
	elseif fields.set_three then
		data:set_string(id.."way3", minetest.serialize(out_pos))
		local way3 = minetest.deserialize(data:get_string(id.."way3"))
		meta:set_string("formspec", get_formspec_o({
			way3 = minetest.deserialize(data:get_string(id.."way3")), -- Refresh formspec
			id = id}))
	elseif fields.use_three then
		meta:set_string("formspec", get_formspec_o({
			x_dest = way3.x, -- Refresh formspec
			y_dest = way3.y,
			z_dest = way3.z,
			id = id}))
		data:set_int(id.."x_dest", way3.x)
		data:set_int(id.."y_dest", way3.y)
		data:set_int(id.."z_dest", way3.z)
	end
end


--------------------
--NODE DEFINITIONS--
--------------------
_drwho_tardis.console_list = {
    "console_y",
    "console_x",
    "console_z",
    "console_c",
    "console_go",
    "console_f",
    "console_o",
    "console_s",
    "light",
    "rotor",
}
local function register_console_set(set, craftitem, side, ytexture, xtexture, ztexture, ftexture, stexture, wtexture, ctexture, otexture, rotortexture, altrotortexture, ltexture)
minetest.register_node("drwho_tardis:console_y"..set, {
		description = S("Axis Console Unit A"),
		tiles = {ytexture, ytexture, side, side, side, side},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos) 
				local out_pos = minetest.deserialize(data:get_string(id.."out_pos")) 
				meta:set_string("id", id) 
				meta:set_string("formspec", get_formspec_fxyz({addy = 0, outy = out_pos.y, id = id})) 
			else minetest.dig_node(pos) end
		end,
		on_rightclick = function(pos, node, clicker, itemstack) 
			local meta = minetest.get_meta(pos)
			local id = meta:get_string("id")
			local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
			meta:set_string("id", id)
			meta:set_string("formspec", get_formspec_fxyz({
				addy = data:get_int(id.."y_dest"), 
				outy = out_pos.y,
				id = id
			}))
		end,
		on_receive_fields = general_functions
})
minetest.register_node("drwho_tardis:console_x"..set, {
		description = S("Axis Console Unit B"),
		tiles = {xtexture, xtexture, side, side, side, side},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then 
				local meta = minetest.get_meta(pos)
				local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
				meta:set_string("id", id)
				meta:set_string("formspec", get_formspec_fxyz({addx = 0, outx = out_pos.x, id = id}))
			else minetest.dig_node(pos) end
		end,
		on_rightclick = function(pos, node, clicker, itemstack)
			local meta = minetest.get_meta(pos)
			local id = meta:get_string("id")
			local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
			meta:set_string("id", id)
			meta:set_string("formspec", get_formspec_fxyz({
				addx = data:get_int(id.."x_dest"), 
				outx = out_pos.x,
				id = id
			}))
		end,
		on_receive_fields = general_functions
})
minetest.register_node("drwho_tardis:console_z"..set, {
		description = S("Axis Console Unit C"),
		tiles = {ztexture, ztexture, side, side, side, side},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos)
				local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
				meta:set_string("id", id)
				meta:set_string("formspec", get_formspec_fxyz({addz = 0, outz = out_pos.z, id = id}))
			else minetest.dig_node(pos) end
		end,
		on_rightclick = function(pos, node, clicker, itemstack)
			local meta = minetest.get_meta(pos)
			local id = meta:get_string("id")
			local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
			meta:set_string("id", id)
			meta:set_string("formspec", get_formspec_fxyz({
				addz = data:get_int(id.."z_dest"), 
				outz = out_pos.z,
				id = id
			}))
		end,
		on_receive_fields = general_functions
})
minetest.register_node("drwho_tardis:console_f"..set, {
		description = S("Find Biome Console Unit"),
		tiles = {ftexture, ftexture, side, side, side, side},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos)
				meta:set_string("id", id)
				meta:set_string("formspec", get_formspec_fb({id = id}))
			else minetest.dig_node(pos) end
		end,
		on_rightclick = function(pos, node, clicker, itemstack)
			local meta = minetest.get_meta(pos)
			local id = meta:get_string("id")
			meta:set_string("id", id)
			meta:set_string("formspec", get_formspec_fb({
				id = id, 
				pos = minetest.deserialize(data:get_string(id.."out_pos"))
			}))
		end,
		on_receive_fields = find_biome_functions
})
minetest.register_node("drwho_tardis:console_s"..set, {
		description = S("Functions Console Unit"),
		tiles = {stexture, stexture, side, side, side, side},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos)
				local id = pmeta:get_string("id")
				meta:set_string("id", id)
				meta:set_string("formspec", get_formspec_s())
			else minetest.dig_node(pos) end
		end,
		on_receive_fields = general_functions
})
minetest.register_node("drwho_tardis:console_go"..set, {
		description = S("Warp Lever Console Unit"),
		tiles = {wtexture, wtexture, side, side, side, side},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos)
				meta:set_string("id", id)
				meta:set_string("formspec", get_formspec_w())
			else minetest.dig_node(pos) end
		end,
		on_receive_fields = travel_to_location
})
minetest.register_node("drwho_tardis:console_c"..set, {
		description = S("Exterior Console Unit"),
		tiles = {ctexture, ctexture, side, side, side, side},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos)
				meta:set_string("id", id)
				meta:set_string("formspec", get_formspec_ext('blue'))
			else minetest.dig_node(pos) end
		end,
		on_receive_fields = change_look
})
minetest.register_node("drwho_tardis:console_o"..set, {
		description = S("Waypoint Console Unit"),
		tiles = {otexture, otexture, side, side, side, side},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos)
				meta:set_string("id", id)
				meta:set_string("formspec", get_formspec_o({id=id}))
			else minetest.dig_node(pos) end
		end,
		on_rightclick = function(pos, node, clicker, itemstack)
			local meta = minetest.get_meta(pos)
			local id = meta:get_string("id")
			local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
			meta:set_string("id", id)
			meta:set_string("formspec", get_formspec_o({
				x_dest = data:get_int(id.."x_dest"), 
				y_dest = data:get_int(id.."y_dest"), 
				z_dest = data:get_int(id.."z_dest"), 
				out_pos = out_pos, -- Current position
				id = id
			}))
		end,
		on_receive_fields = waypoint
})
minetest.register_node("drwho_tardis:rotor"..set, {
		description = S("Time Rotor"),
		tiles = {rotortexture},
		drawtype = "mesh",
		use_texture_alpha = "clip",
		mesh = "tardis.obj",
		selection_box = {type = "fixed", fixed = { { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 } }},
		collision_box = {type = "fixed", fixed = { { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 } }},
		light_source = 10,
		groups = {cracky = 1, tardis_time_rotor = 1},
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos)
				meta:set_string("id", id)
				meta:set_string("formspec", get_formspec_r(data:get_int(id.."power")))
				meta:set_string("style", set)
				data:set_string(id.."r_pos", minetest.serialize(pos))
				local timer = minetest.get_node_timer(pos)
				timer:start(15)
			else minetest.dig_node(pos) end
		end,
		on_rightclick = function(pos, node, clicker, itemstack)
			local meta = minetest.get_meta(pos)
			local id = meta:get_string("id")
			meta:set_string("formspec", get_formspec_r(data:get_int(id.."power")))
		end,
		on_timer = function(pos)
			local meta = minetest.get_meta(pos)
			local id = meta:get_string("id")
			local max_power = tonumber(minetest.settings:get('drwho_tardis.max_power')) or 10
			if data:get_int(id.."power") < max_power then data:set_int(id.."power", data:get_int(id.."power")+1) end
			meta:set_string("formspec", get_formspec_r(data:get_int(id.."power")))
			if data:get_string(id.."r_pos") == minetest.serialize(pos) then return true else return false end
		end
})
minetest.register_node("drwho_tardis:rotor_active"..set, {
		description = S("Time Rotor (active)"),
		tiles = { {name = altrotortexture, animation = {type = "vertical_frames", aspect_w = 64, aspect_h = 64, length = 1.5}} },
		drawtype = "mesh",
		use_texture_alpha = "clip",
		mesh = "tardis.obj",
		selection_box = {type = "fixed", fixed = { { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 } }},
		collision_box = {type = "fixed", fixed = { { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 } }},
		light_source = 12,
		groups = {not_in_creative_inventory = 1, tardis_time_rotor_active = 1},
})
minetest.register_node("drwho_tardis:light"..set, {
		description = S("Tardis Light"),
		inventory_image = ltexture,
		drawtype = "signlike",
		paramtype = "light",
		sunlight_propagates = true,
		walkable = false, -- Allow players to walk thru them (rather than blocking their movement)
		light_source = minetest.LIGHT_MAX, -- VERY bright
		paramtype2 = "wallmounted",
		selection_box = { type = "wallmounted" },
		tiles = {ltexture},
		groups = {oddly_breakable_by_hand = 1}
})

-- Loop function to register crafting recipes for the variations
if craftitem == "" then return else
    for _, item in ipairs(_drwho_tardis.console_list) do
        minetest.register_craft({
            output = "drwho_tardis:"..item..set, -- e.g. drwho_tardis:console_s_2
            recipe = {
                {craftitem},
                {"drwho_tardis:"..item}
            }
        })
    end -- of for loop
end
end -- of register_console_set()

local i = _drwho_tardis.items
-- Register all three sets
register_console_set("", "", "tardis_side_1.png", "y_console_1.png", "x_console_1.png", "z_console_1.png", "f_console_1.png", "s_console_1.png", "w_console_1.png", "c_console_1.png", "o_console_1.png", "rotor_1.png", "alt_rotor_1.png", "tardis_light_1.png")
register_console_set("_2", "group:wood", "tardis_side_2.png", "y_console_2.png", "x_console_2.png", "z_console_2.png", "f_console_2.png", "s_console_2.png", "w_console_2.png", "c_console_2.png", "o_console_2.png", "rotor_2.png", "alt_rotor_2.png", "tardis_light_2.png")
register_console_set("_3", i.silver_sand, "tardis_side_3.png", "y_console_3.png", "x_console_3.png", "z_console_3.png", "f_console_3.png", "s_console_3.png", "w_console_3.png", "c_console_3.png", "o_console_3.png", "rotor_3.png", "alt_rotor_3.png", "tardis_light_3.png")

-- TARDIS Monitor Screen
local function get_formspec_screen(power, posx, posy, posz, desx, desy, desz, block, id)
	local power = S("Tardis Energy Banks: @1", power) -- Tardis Energy Banks: 8
	local cur = S("Current Position: @1, @2, @3", posx, posy, posz)
	local dest = S("Destination: @1, @2, @3", desx, desy, desz)
	local block = block
	local id = S("Tardis Owner: @1", id) -- Tardis Owner: <name>
    return "size[10,10]"..
		"label[1,1;"..minetest.formspec_escape(power).."]"..
		"label[1,2.5;"..minetest.formspec_escape(cur).."]"..
		"label[1,4;"..minetest.formspec_escape(dest).."]"..
		"label[1,5.5;"..minetest.formspec_escape(S("Block Tardis Is On: ")).."]"..
		"item_image[3,5;2,2;"..minetest.formspec_escape(block).."]"..
		"label[1,7;"..minetest.formspec_escape(id).."]"
end
minetest.register_node("drwho_tardis:monitor", {
		description = S("Tardis Monitor"),
		tiles = {"tardis_side_1.png", "tardis_side_1.png", "tardis_side_1.png", "tardis_side_1.png", "tardis_monitor_screen.png", "tardis_side_1.png"},
		drawtype = "nodebox",
		node_box = {
			type = "fixed",
			fixed = {
				{ -0.5, -0.4, 0.1, 0.5,  0.4, 0 },
				{ 0.1, 0.1, 0, -0.1, -0.1, -0.5},
			},
		},
		groups = {cracky = 3},
		paramtype2 = "4dir",
		after_place_node = function(pos, placer, itemstack, pointed_thing)
			local pmeta = placer:get_meta()
			local id = pmeta:get_string("id")
			local r_pos = minetest.deserialize(data:get_string(id.."r_pos"))
			if not r_pos then r_pos = placer:get_pos() end
			if r_pos.x+50 > pos.x and r_pos.x-50 < pos.x and r_pos.z+50 > pos.z and r_pos.z-50 < pos.z and r_pos.y+50 > pos.y and r_pos.y-50 < pos.y then
				local meta = minetest.get_meta(pos)
				local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
				meta:set_string("id", id)
		
				out_pos.y = out_pos.y-1
				local node = minetest.get_node(out_pos)
				if node.name == "ignore" then
					minetest.get_voxel_manip():read_from_map(out_pos, out_pos)
					local node = minetest.get_node(out_pos)
				end
				out_pos.y = out_pos.y+1
		
				meta:set_string("formspec", get_formspec_screen(data:get_int(id.."power"), out_pos.x, out_pos.y, out_pos.z, data:get_int(id.."x_dest"), data:get_int(id.."y_dest"), data:get_int(id.."z_dest"), node.name, id ))
			else minetest.dig_node(pos) end
		end,
		on_rightclick = function(pos)
			local meta = minetest.get_meta(pos)
			local id = meta:get_string("id")
			local out_pos = minetest.deserialize(data:get_string(id.."out_pos"))
		
			out_pos.y = out_pos.y-1
			local node = minetest.get_node(out_pos)
			if node.name == "ignore" then
				minetest.get_voxel_manip():read_from_map(out_pos, out_pos)
				local node = minetest.get_node(out_pos)
			end
			out_pos.y = out_pos.y+1
		
			meta:set_string("formspec", get_formspec_screen(data:get_int(id.."power"), out_pos.x, out_pos.y, out_pos.z, data:get_int(id.."x_dest"), data:get_int(id.."y_dest"), data:get_int(id.."z_dest"), node.name, id ))
		end -- end TARDIS Monitor
})