-- LUALOCALS < ---------------------------------------------------------
local addgroups, get_mod_api, math, minetest, piredo_map,
      piredo_player, posrel, vector
    = addgroups, get_mod_api, math, minetest, piredo_map,
      piredo_player, posrel, vector
local math_pi
    = math.pi
-- LUALOCALS > ---------------------------------------------------------

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

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

local function expect(pos, group)
	return minetest.get_item_group(minetest.get_node(pos).name, group) > 0
end

local function winstate(rel)
	piredo_player.discover("solve:final")
	piredo_map.statedb.final_done = true
	piredo_map.savedb()
	piredo_map.transfer_changes("special_final_room_2")
	api.magic(rel(0.5, -0.5, 0.5), true)
	piredo_map.putschem(rel(-9, 31, -9), "special_final_room_2")
	piredo_map.set_current_room(rel(-9, 31, -9), "special_final_room_2")
	for rx = 0, 1 do
		for ry = -1, 0 do
			for rz = 0, 1 do
				api.magic(rel(rx, ry, rz))
			end
		end
	end
end

minetest.override_item("piredo_terrain:piranesi__chess_totem", {
		on_construct = function(pos)
			minetest.after(0, function()
					local rel = posrel(pos)
					if expect(rel(0, -1, 0), "totem_altar")
					and expect(rel(1, -1, 0), "totem_altar")
					and expect(rel(1, -1, 1), "totem_altar")
					and expect(rel(0, -1, 1), "totem_altar")
					and expect(rel(1, 0, 0), "totem_neck")
					and expect(rel(1, 0, 1), "totem_time")
					and expect(rel(0, 0, 1), "totem_coin") then
						minetest.remove_node(rel(0, 0, 0))
						minetest.remove_node(rel(1, 0, 0))
						minetest.remove_node(rel(1, 0, 1))
						minetest.remove_node(rel(0, 0, 1))
						return winstate(rel)
					end
				end)
		end
	})

addgroups("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
		local rel = posrel(vector.round(player:get_pos()))
		piredo_map.putschem(rel(-20, 60, -16), "outside_ruined")
		ruinpos = rel(-0.5, 66, 18.5)
		modstore:set_string("ruinpos", minetest.serialize(ruinpos))
	end
	piredo_player.screenfade(player)
	minetest.after(0, function()
			piredo_player.discover("solve:final_warp")
			piredo_player.stop_timer()
			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(
				posrel(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 rel = posrel(ruinpos)
			local exit = rel(-7.5, -5.5, -29.5)
			if vector.distance(pos, exit) < 3 then
				piredo_player.set_endcredits(rel(-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)
