-- LUALOCALS < ---------------------------------------------------------
local ipairs, math, minetest, piredo_api, piredo_map, piredo_player,
      vector
    = ipairs, math, minetest, piredo_api, piredo_map, piredo_player,
      vector
local math_pi
    = math.pi
-- LUALOCALS > ---------------------------------------------------------

local api = piredo_api.get_mod_api()
local modstore = minetest.get_mod_storage()

piredo_api.add_groups("piredo_terrain:piranesi__chess_totem", "totem_chess")
piredo_api.add_groups("piredo_terrain:piranesi__neck_totem", "totem_neck")
piredo_api.add_groups("piredo_terrain:piranesi__coin_totem", "totem_coin")
piredo_api.add_groups("piredo_terrain:piranesi__time_totem", "totem_time")
piredo_api.add_groups("piredo_terrain:piranesi__altar", "totem_altar")

local totemnodes = {
	{pos = vector.new(0, 0, 0), group = "totem_chess"},
	{pos = vector.new(1, 0, 0), group = "totem_neck"},
	{pos = vector.new(1, 0, 1), group = "totem_time"},
	{pos = vector.new(0, 0, 1), group = "totem_coin"},
	{pos = vector.new(0, -1, 0), group = "totem_altar"},
	{pos = vector.new(1, -1, 0), group = "totem_altar"},
	{pos = vector.new(1, -1, 1), group = "totem_altar"},
	{pos = vector.new(0, -1, 1), group = "totem_altar"},
}

local function final_altar_check(pos)
	for _, v in ipairs(totemnodes) do
		local p = vector.add(pos, v.pos)
		local nn = minetest.get_node(p).name
		if minetest.get_item_group(nn, v.group) == 0 then return end
	end
	piredo_player.discover("solve:final")
	piredo_map.statedb.final_done = true
	piredo_map.savedb()
	piredo_map.transfer_changes("special_final_room_2")
	piredo_map.putschem(vector.offset(pos, -9, 31, -9), "special_final_room_2")
	piredo_map.set_current_room(vector.offset(pos, -9, 31, -9), "special_final_room_2")
	api.magic(vector.offset(pos, 0.5, -0.5, 0.5), true)
	for _, v in ipairs(totemnodes) do
		local p = vector.add(pos, v.pos)
		minetest.set_node(p, {name = "piredo_terrain:ambient"})
		api.magic(p)
	end
end

minetest.override_item("piredo_terrain:piranesi__chess_totem", {
		on_construct = function(pos)
			minetest.after(0, final_altar_check, pos)
		end
	})

piredo_api.add_groups("piredo_terrain:piranesi__end", "final_end_warp")

local teleport_pending
local ruinpos = modstore:get_string("ruinpos")
ruinpos = ruinpos and ruinpos ~= "" and minetest.deserialize(ruinpos)

local function teleport_to_ruin(player)
	teleport_pending = true

	if not ruinpos then
		ruinpos = vector.offset(vector.round(player:get_pos()), -0.5, 66, 18.5)
		modstore:set_string("ruinpos", minetest.serialize(ruinpos))
	end
	piredo_map.putschem(vector.offset(ruinpos, -19.5, -6, -34.5), "outside_ruined")
	piredo_player.screenfade(player)
	minetest.after(0, function()
			piredo_player.discover("solve:final_warp")
			teleport_pending = nil
			local mp = piredo_player.mainplayer()
			if not mp then return end
			local inv = mp:get_inventory()
			for i = 1, inv:get_size("main") do inv:set_stack("main", i, "") end
			mp:set_pos(ruinpos)
			mp:set_look_horizontal(math_pi)
			mp:set_look_vertical(0)
			piredo_map.set_current_room(
				vector.offset(ruinpos, -19.5, -6, -34.5), "outside_ruined")
			piredo_map.statedb.daytime = 0.75
			piredo_map.savedb()
		end)
end

piredo_player.register_playerstep(function(player)
		if teleport_pending then return end
		local pos = player:get_pos()

		if ruinpos and pos.y >= ruinpos.y - 6 then
			local exit = vector.offset(ruinpos, -7.5, -5.5, -29.5)
			if vector.distance(pos, exit) < 3 then
				piredo_player.stop_timer()
				piredo_player.set_endcredits(vector.offset(ruinpos, -7.5, 0, -20))
			end
		end

		pos.y = pos.y + 0.49
		local node = minetest.get_node(pos)
		if minetest.get_item_group(node.name, "final_end_warp") > 0 then
			return teleport_to_ruin(player)
		end
	end)
