local ms = minetest.get_mod_storage()

minetest.after(0.5, function()
	minetest.place_schematic({x=0,y=0,z=0}, minetest.get_modpath("ld_game") .. "/schems/hub.mts", "0", {}, true)
end)

local function gsay(msg)
	minetest.chat_send_all(minetest.colorize("#FCF1AC", ">>> " .. msg))
end

local function gdm(name, msg)
	minetest.chat_send_player(name, minetest.colorize("#FCF1AC", ">>> " .. msg))
end

local function edit_pts(name, pts)
	local pstats = minetest.deserialize(ms:get("pts")) or {}
	if pstats[name] then
		if pstats[name] + pts >= 0 then
			pstats[name] = pstats[name] + pts
		else
			pstats[name] = 0
		end
	else
		if pts >= 0 then
			pstats[name]= pts
		end
	end
	ms:set_string("pts", minetest.serialize(pstats))
end

local function get_pts(name)
	local pstats = minetest.deserialize(ms:get("pts")) or {}
	if pstats[name] then
		return true, pstats[name]
	else
		return false, -1
	end
end

local plimit = minetest.settings:get("luckydude_playerlimit") or 3
local rnumber = math.random(1, 4)
local count = 0
local mtbl = {}
local wmsgs = {"Hey ", "Hello ", "Hi ", "Heyo ", "Hii ", "Hai "}
local lmsgs = {"Oops! ", "Oh no! ", "Ouch! ", "Uh oh... ", "Oof... ", "Sigh... "}
local gmsgs = {"Yay!", "Well done!", "Good job!", "Nice one!", "Hooray!", "Congrats!", "Not bad!"}
local bmsgs = {"Bye ", "Bye bye ", "See you ", "Cya ", "Until next time "}

local function check_node(pos, puncher)
	local pname = puncher:get_player_name()
	if minetest.registered_nodes[minetest.get_node(pos).name]["nid"] == rnumber then
		if count == 3 then
			minetest.sound_play("right", {}, true)
			gsay(gmsgs[math.random(1, #gmsgs)])
			minetest.set_node(pos, {name="ld_game:right"})
		else
			minetest.sound_play("wrong", {}, true)
			gsay(lmsgs[math.random(1, #lmsgs)] .. "Player " .. pname .. " hit the wrong cube...")
			edit_pts(pname, -3)
			minetest.set_node(pos, {name="ld_game:wrong"})
		end
		local postbl, _ = minetest.find_nodes_in_area({x=0,y=1.5,z=4}, {x=0,y=2.5,z=5}, {"ld_game:node_1", "ld_game:node_2", "ld_game:node_3", "ld_game:node_4"})
		for k, v in pairs(postbl) do
			minetest.set_node(v, {name="ld_game:late"})
		end
		count = 0
		minetest.after(3, function()
			minetest.place_schematic({x=0,y=1.5,z=4}, minetest.get_modpath("ld_game") .. "/schems/nodes.mts", "0", {}, true)
			rnumber = math.random(1, 4)
		end)
	else
		minetest.sound_play("plop", {}, true)
		minetest.set_node(pos, {name="ld_game:dead"})
		edit_pts(pname, 2)
		count = count + 1
	end
end

-- JOIN/LEAVE/MSGS
function minetest.send_leave_message(pname, timed_out)
	gsay("*** " .. bmsgs[math.random(1, #bmsgs)] .. pname)
end

function minetest.send_join_message(pname)
	gsay("*** " .. wmsgs[math.random(1, #wmsgs)] .. pname)
end

minetest.register_on_prejoinplayer(function(name, ip)
	if #minetest.get_connected_players() >= plimit then
		return "There are already " .. plimit .. " players in this game, please try again later."
	end
end)

minetest.register_on_joinplayer(function(player, last_login)
	local pname = player:get_player_name()
	player:hud_set_flags({hotbar=false, healthbar=false, wielditem=false, breathbar=false, minimap=false, minimap_radar=false})
	player:set_pos({x=math.random(2.5, 4.5),y=1,z=math.random(1.5, 7.5)})
	player:set_look_horizontal(math.pi/2)
	gdm(pname, "Welcome to the game! Need help? Try /luckydude")
	if ms:get_string("m_"..pname) ~= "n" then
		ms:set_string("m_"..pname, "y")
		mtbl[pname] = minetest.sound_play("sparks", {to_player=pname, gain=0.1, loop=true})
	else
		minetest.chat_send_player(pname, minetest.colorize("#FCF1AC", "[Music] OFF, /music to turn it on"))
	end
end)

-- NODES
minetest.register_node("ld_game:barrier", {
	description = "Barrier",
	tiles = {"ld_barrier.png"},
	pointable = false
})

minetest.register_node("ld_game:dead", {
	description = "Dead Node",
	tiles = {"ld_dead.png"}
})

minetest.register_node("ld_game:late", {
	description = "Late Node",
	tiles = {"ld_late.png"}
})

minetest.register_node("ld_game:right", {
	description = "Right Node",
	tiles = {"ld_right.png"}
})

minetest.register_node("ld_game:wrong", {
	description = "Wrong Node",
	tiles = {"ld_wrong.png"}
})

minetest.register_node("ld_game:light", {
	paramtype = "light",
	description = "Light",
	tiles = {"ld_light.png"},
	light_source = minetest.LIGHT_MAX,
	pointable = false
})

minetest.register_node("ld_game:node_1", {
	description = "Node 1", -- petrol
	tiles = {"ld_node_1.png"},
	nid = 1,
	on_punch = function(pos, node, puncher, pointed_thing)
		check_node(pos, puncher)
	end
})

minetest.register_node("ld_game:node_2", {
	description = "Node 2", -- violet
	tiles = {"ld_node_2.png"},
	nid = 2,
	on_punch = function(pos, node, puncher, pointed_thing)
		check_node(pos, puncher)
	end
})

minetest.register_node("ld_game:node_3", {
	description = "Node 3", -- ocher
	tiles = {"ld_node_3.png"},
	nid = 3,
	on_punch = function(pos, node, puncher, pointed_thing)
		check_node(pos, puncher)
	end
})

minetest.register_node("ld_game:node_4", {
	description = "Node 4", -- lime
	tiles = {"ld_node_4.png"},
	nid = 4,
	on_punch = function(pos, node, puncher, pointed_thing)
		check_node(pos, puncher)
	end
})

-- FS
local ld_content = minetest.colorize("#FCF1AC", "LuckyDude Help\n\n") ..
minetest.colorize("#FCF1AC", "How do I play this game?\n") .."Your goal is to guess which cube needs to be hit last. If the cube you hit turns grey it's all good, you can go on.\n" ..
"If the cube turns red, then you've hit this cube too early... If the cube turns green you succeeded! A new game\nwill start shortly.\n" ..
minetest.colorize("#FCF1AC", "\nCan I play this with friends?\n") ..
"Yes you can! The player limit can be tweaked in the game's settings. Keep in mind that it can get a bit crowded\nand thus confusing when too many players are in game at the same time.\n" ..
minetest.colorize("#FCF1AC", "\nAre there different levels?\n") ..
"No, unfortunately not yet. However this could be coming in a future update.\nStay tuned!\n" ..
minetest.colorize("#FCF1AC", "\nHow can I compete with others?\n") ..
"For every cube that turns grey you receive 2 points. For every cube that turns green you get 0 points. BUT!\nIf you hit a cube and it turns red you lose 3 points!\nCheck your own or someone else's score by tpying /pts <name>\n" ..
minetest.colorize("#FCF1AC", "\nWhat else do I need to know?\n") ..
"Make sure to be a lucky dude! Apart from that? Not much really, GLHF!"

local ld_help = "formspec_version[4]" ..
"size[18,12]" ..
"no_prepend[]" ..
"bgcolor[#000000AA;false]" ..
"style_type[button;bgcolor=#00FFCC]" ..
"position[0.5,0.5]" ..
"anchor[0.5,0.5]" ..
"label[0.3,0.5;" .. ld_content .."]" ..
"style_type[button_exit;bgcolor=#FF0000]" ..
"button_exit[17.3,0.2;0.5,0.5;exit;-]"

-- PRIVS
minetest.register_privilege("ld_admin", {
	description = "Administrate luckydude (points)",
	give_to_singleplayer = false
})

-- CMDS
minetest.register_chatcommand("luckydude", {
	description = "Get help on how to play the game",
	func = function(name)
		gdm(name, "Displaying help...")
		minetest.show_formspec(name, "ld_game:ld_help", ld_help)
	end
})

minetest.register_chatcommand("pts", {
	description = "Show score.",
	params = "[<name>]",
	func = function(name, param)
		if param == "" or nil then
			param = name
		end
		local _, pts = get_pts(param)
		if pts == -1 then
			gdm(name, "Player " .. param .. " has no records.")
		else
			gdm(name, "Points of " .. param .. ": " .. pts)
		end
	end
})

minetest.register_chatcommand("reset_pts", {
	description = "Reset score.",
	params = "[<name>]",
	func = function(name, param)
		if param == "" or param == name then
			param = name
		elseif not minetest.check_player_privs(name, {ld_admin=true}) then
			return
			gdm(name, "Insufficient privileges!")
		end
		local _, pts = get_pts(param)
		if pts == -1 then
			gdm(name, "Player " .. param .. " has no records.")
		else
			edit_pts(param, pts*-1)
			gdm(name, "Score of " .. param .. " has been reset!")
		end
	end
})

minetest.register_chatcommand("music", {
	description = "Toggle music.",
	func = function(name)
		if ms:get_string("m_"..name) == "y" then
			minetest.sound_stop(mtbl[name])
			mtbl[name] = nil
			ms:set_string("m_"..name, "n")
			minetest.chat_send_player(name, minetest.colorize("#FCF1AC", "[Music] OFF"))
		else
			ms:set_string("m_"..name, "y")
			mtbl[name] = minetest.sound_play("sparks", {to_player=name, gain=0.1, loop=true})
			minetest.chat_send_player(name, minetest.colorize("#FCF1AC", "[Music] ON"))
		end
	end
})