--[[ init.lua
Copyright 2025 Pixelo789

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

SPDX-License-Identifier: AGPL-3.0-or-later
--]]


local modname = core.get_current_modname()
local S = core.get_translator(modname)
local modpath = core.get_modpath(modname)

local pi = math.pi

local sna = thinkingwitharrows.set_node_area
local snam = thinkingwitharrows.set_node_area_multiple
local sn = core.set_node
local bsn = core.bulk_set_node
local rn = core.remove_node
local na = thinkingwitharrows.node_area

local get_gametime = core.get_gametime


-- Colors
local DEFAULT_COLOR = 0xFFFFFF
local AI_COLOR = 0x00FF00
local SYSTEM_COLOR = 0x17C2EF
local GAME_COLOR = 0xF28748

local self_destruct_jobs = {}


-- Helper function for button swapping levels
local function button_swap_helper(num, t)
	local orange, blue, button
	if num == 1 then
		orange = {name = "thinkingwitharrows_nodes:concrete_orange"}
		blue = {name = "air"}
		button = {name = "thinkingwitharrows_buttons:button_block_2"}
	else
		blue = {name = "thinkingwitharrows_nodes:concrete_light_blue"}
		orange = {name = "air"}
		button = {name = "thinkingwitharrows_buttons:button_block_1"}
	end

	-- oranges
	local oranges = {}
	if t.oranges then
		for _, v in ipairs(t.oranges) do
			local new_nodes = thinkingwitharrows.node_area(v[1], v[2])
			for _, v2 in ipairs(new_nodes) do
				table.insert(oranges, v2)
			end
		end
	end
	if t.oranges_standalone then
		for _, v in ipairs(t.oranges_standalone) do
			table.insert(oranges, v)
		end
	end
	bsn(oranges, orange)

	-- blues
	local blues = {}
	if t.blues then
		for _, v in ipairs(t.blues) do
			local new_nodes = thinkingwitharrows.node_area(v[1], v[2])
			for _, v2 in ipairs(new_nodes) do
				table.insert(blues, v2)
			end
		end
	end
	if t.blues_standalone then
		for _, v in ipairs(t.blues_standalone) do
			table.insert(blues, v)
		end
	end
	bsn(blues, blue)

	-- buttons
	if t.buttons then
		bsn(t.buttons, button)
	end
end


-- Checks if two positions are equal
local function pos_equal(p1, p2)
	return p1.x == p2.x and p1.y == p2.y and p1.z == p2.z
end


-- Level 16 repeats the same section, so this variable is for convenience
local level_16_t = {
	oranges = {
		{{x = 7, y = 6, z = 6}, {x = 11, y = 9, z = 6}},
		{{x = 7, y = 15, z = 1}, {x = 11, y = 15, z = 5}},
		{{x = 6, y = 21, z = 13}, {x = 6, y = 24, z = 17}},
		{{x = 8, y = 15, z = 12}, {x = 8, y = 18, z = 12}},
	},
	blues = {
		{{x = 1, y = 14, z = 13}, {x = 5, y = 14, z = 17}},
		{{x = 7, y = 10, z = 1}, {x = 11, y = 10, z = 5}},
		{{x = 7, y = 20, z = 1}, {x = 11, y = 20, z = 5}},
		{{x = 12, y = 21, z = 13}, {x = 12, y = 24, z = 17}},
		{{x = 10, y = 15, z = 12}, {x = 10, y = 18, z = 12}},
	},
	buttons = {
		{x = 9, y = 8, z = 9},
		{x = 8, y = 18, z = 9},
		{x = 10, y = 18, z = 9},
	},
}


function thinkingwitharrows.stop_self_destruct()
	for _, v in ipairs(self_destruct_jobs) do
		v:cancel()
	end
	self_destruct_jobs = {}
end


-- Helper function for self destruct jobs
local function level21_jobs(player, offset)
	local meta = player:get_meta()

	local offset = offset or 0
	if offset >= 300 then
		thinkingwitharrows.change_level_secondary(player, 20)
		return
	end

	if meta:get_int("level21_destruct_time") == 0 then
		meta:set_int("level21_destruct_time", get_gametime() + 300)
	end

	local times = {
		[60] = "FOUR MINUTES",
		[120] = "THREE MINUTES",
		[180] = "TWO MINUTES",
		[240] = "ONE MINUTE",
		[270] = "THIRTY SECONDS",
		[290] = "TEN SECONDS",
	}
	for k, v in pairs(times) do
		if k - offset > 0 then
			table.insert(self_destruct_jobs, core.after(k - offset, function(aplayer)
				thinkingwitharrows_dialogue.queue_dialogue(aplayer, {string.format("This facility will self-destruct in: %s", v)}, {SYSTEM_COLOR})
			end, player))
		end
	end
	table.insert(self_destruct_jobs, core.after(300 - offset, function(aplayer)
		thinkingwitharrows_dialogue.queue_dialogue(aplayer, {
			"This facility will self-destruct in: NOW",
			"Looks like I win after all...",
		}, {
			SYSTEM_COLOR,
			AI_COLOR,
		}, function(aplayer)
			thinkingwitharrows.change_level_secondary(aplayer, 20)
		end)
	end, player))
end



function thinkingwitharrows.get_levels() return {
	-- level 1
	{sections = {
		{
			pos = {x = 3, y = 2.5, z = 3}, rotate = 0,
			clear_inventory = true,
			dialogue = {
				"Hello Test Subject.",
				"You have been randomly selected to undertake an examination.",
				"You will be required to solve puzzles using ancient weaponry.",
				"These tests are valid scientific research.",
				"We definitely did not run out of ideas for what to do.",
				"...",
				"The thing in front of you is a target.",
				"Interact with the target to proceed to the next stage.",
				"The testing has now begun. Good luck.",
				"Walk forward and interact with the button.",
				"You can also sprint (walk faster) with Aux1.",
			},
			dialogue_colors = {
				[10] = GAME_COLOR,
				[11] = GAME_COLOR,
			}
		},
		{
			pos = {x = 11, y = 2.5, z = 3}, rotate = 0,
			clear_inventory = true,
			dialogue = {
				"Be careful in this section.",
				'Use the "Jump" key to jump the gap.',
			},
			dialogue_colors = {
				[2] = GAME_COLOR,
			}
		},
	}, fake_levels = S("%s/7"), arrows = 0},
	-- level 2
	{sections = {
		{
			pos = {x = 3, y = 2.5, z = 3}, rotate = pi / 2,
			clear_inventory = true,
			dialogue = {
				"Congratulations. You have done the bare minimum to obtain your ancient weaponry.",
				"Interact with that thing in front of you to obtain it.",
				"Mind the gap.",
				'Use the "Place" key to load the bow.',
				'Then use the "Punch" key to fire the bow.',
				"If you run out of arrows, interact with the arrow block to get more."
			},
			dialogue_colors = {
				[4] = GAME_COLOR,
				[5] = GAME_COLOR,
				[6] = GAME_COLOR,
			}
		},
		{
			pos = {x = 11, y = 2.5, z = 1}, rotate = pi / 2,
			dialogue = {
				"Hit the bullsyes, and you might win a prize.",
				"We apologize for not mentioning that earlier."
			}
		},
		{
			pos = {x = 4, y = 11.5, z = 18}, rotate = pi / 2,
			dialogue = {
				'You may be wondering: "What kind of research am I contributing to?"',
				"We are still figuring out the details,",
				"but we believe this could contribute to the following fields:",
				"Psychology, Agronomy, Dermatology, Cosmetology,",
				"and many other fields you have not heard of.",
			},
			easy_tweaks = function(player)
				sn({x = 23, y = 22, z = 20}, {name = "thinkingwitharrows_bows:arrow_block"})
			end
		},
	}, fake_levels = S("%s/7"), arrows = 0},
	-- level 3
	{sections = {
		{
			pos = {x = 3, y = 2.5, z = 3}, rotate = pi / -2,
			button_callback = function(_, num)
				if num == 1 then
					sna({x = 6, y = 3, z = 19}, {x = 6, y = 6, z = 23})
				else
					sna({x = 6, y = 3, z = 1}, {x = 6, y = 6, z = 5})
				end
			end,
			dialogue = {
				"That thing is a button. Interact with the button to do stuff.",
				"We're not sure what the button does yet.",
				"We were too afraid to press it.",
				"Shoot or interact with the button to activate it."
			},
			dialogue_colors = {
				[4] = GAME_COLOR,
			}
		},
		{
			pos = {x = 17, y = 3.5, z = 3}, rotate = pi / 2,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 16, y = 4, z = 17}, {x = 18, y = 4, z = 19}},
						{{x = 16, y = 8, z = 17}, {x = 18, y = 8, z = 19}},
						{{x = 16, y = 12, z = 17}, {x = 18, y = 12, z = 19}},
					},
					blues = {
						{{x = 16, y = 6, z = 17}, {x = 18, y = 6, z = 19}},
						{{x = 16, y = 10, z = 17}, {x = 18, y = 10, z = 19}},
						{{x = 16, y = 14, z = 17}, {x = 18, y = 14, z = 19}},
					},
					buttons = {
						{x = 15, y = 9, z = 18},
						{x = 19, y = 9, z = 18},
					},
				})
			end,
			dialogue = {
				"The buttons are not supposed to be sentient.",
				"If the button speaks, we kindly ask that you disregard its advice.",
			}
		},
	}, fake_levels = S("%s/7"), arrows = 10},
	-- level 4
	{sections = {
		{
			pos = {x = 3, y = 3.5, z = 3}, rotate = pi,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 1, y = 3, z = 18}, {x = 5, y = 3, z = 22}},
						{{x = 1, y = 8, z = 15}, {x = 2, y = 8, z = 16}},
						{{x = 1, y = 11, z = 1}, {x = 2, y = 11, z = 1}},
						{{x = 1, y = 12, z = 11}, {x = 1, y = 12, z = 12}},
						{{x = 1, y = 12, z = 21}, {x = 1, y = 12, z = 22}},
						{{x = 1, y = 19, z = 23}, {x = 1, y = 19, z = 24}},
						{{x = 1, y = 20, z = 19}, {x = 2, y = 23, z = 19}},
						{{x = 1, y = 20, z = 11}, {x = 2, y = 23, z = 11}},
					}, blues = {
						{{x = 1, y = 3, z = 10}, {x = 5, y = 3, z = 14}},
						{{x = 1, y = 8, z = 21}, {x = 2, y = 8, z = 22}},
						{{x = 1, y = 8, z = 9}, {x = 2, y = 8, z = 10}},
						{{x = 1, y = 9, z = 1}, {x = 2, y = 9, z = 1}},
						{{x = 5, y = 12, z = 6}, {x = 5, y = 12, z = 7}},
						{{x = 5, y = 12, z = 16}, {x = 5, y = 12, z = 17}},
						{{x = 4, y = 20, z = 15}, {x = 5, y = 23, z = 15}},
						{{x = 4, y = 20, z = 7}, {x = 5, y = 23, z = 7}},
					}, buttons = {
						{x = 3, y = 6, z = 16},
						{x = 3, y = 21, z = 13},
					}, oranges_standalone = {
						{x = 2, y = 15, z = 27},
					}, blues_standalone = {
						{x = 4, y = 13, z = 27},
						{x = 1, y = 17, z = 26},
					},
				})
			end,
			dialogue = {
				"If this is too much, rest assured that monkeys have completed this test.",
				"Since your species comes from monkeys, you should be able to solve this.",
			}
		},
	}, fake_levels = S("%s/7"), arrows = 15},
	-- level 5
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 3}, rotate = pi,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 14, y = 4, z = 12}, {x = 14, y = 7, z = 16}},
						{{x = 20, y = 4, z = 6}, {x = 20, y = 7, z = 10}},
						{{x = 9, y = 4, z = 5}, {x = 13, y = 7, z = 5}},
					}, blues = {
						{{x = 20, y = 4, z = 12}, {x = 20, y = 7, z = 16}},
						{{x = 21, y = 4, z = 11}, {x = 25, y = 7, z = 11}},
						{{x = 14, y = 4, z = 6}, {x = 14, y = 7, z = 10}},
					}, buttons = {
						{x = 7, y = 5, z = 21},
						{x = 17, y = 16, z = 8},
						{x = 17, y = 5, z = 14},
						{x = 25, y = 5, z = 18},
					}, oranges_standalone = {
						{x = 25, y = 5, z = 17},
					}, blues_standalone = {
						{x = 7, y = 5, z = 17},
					},
				})
			end,
			dialogue = {
				"We may have lost some of the buttons in this test.",
				"Some of our researchers are very clumsy.",
				"If you can't find any buttons, we suggest you look harder.",
			}
		},
	}, fake_levels = S("%s/7")},
	-- level 6
	{sections = {
		{
			pos = {x = 3, y = 2.5, z = 3}, rotate = 0,
			dialogue = {
				"The green boxes can be broken.",
				"Try using them to climb up.",
				"If you try escaping with them, you will be reported.",
				"Your complimentary food access will also be taken away.",
				'Break the green boxes using the "Punch" key.',
			},
			dialogue_colors = {
				[5] = GAME_COLOR,
			}
		},
	}, fake_levels = S("%s/7"), arrows = 0},
	-- level 7
	{sections = {
		{
			pos = {x = 3, y = 8.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 7, y = 9, z = 18}, {x = 11, y = 12, z = 18}},
						{{x = 7, y = 14, z = 18}, {x = 11, y = 17, z = 18}},
					}, blues = {
						{{x = 7, y = 13, z = 22}, {x = 11, y = 13, z = 23}},
						{{x = 12, y = 14, z = 13}, {x = 12, y = 17, z = 17}},
					}, buttons = {
						{x = 17, y = 9, z = 15},
						{x = 26, y = 9, z = 21},
						{x = 9, y = 25, z = 18},
					},
				})
			end,
			dialogue = {
				"Some Test Subjects have reported nausea and dizziness while solving this test.",
				"We hope those same symptoms don't apply to you.",
				"In case you do pass out during this test,",
				"our team of real medical experts will come and revive you.",
				"If that happens, please be patient. They may take a while.",
			}
		},
	}, fake_levels = S("%s/7")},
	-- level 8
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 3}, rotate = 0,
			dialogue = {
				"Shoot the blue things with arrows.",
				"They will reflect the arrow in a different direction.",
			}
		},
		{
			pos = {x = 17, y = 0.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				if num == 1 then
					sna({x = 26, y = 5, z = 13}, {x = 26, y = 9, z = 17})
				end
			end
		},
	}, fake_levels = S("%s/7?")},
	-- level 9
	{sections = {
		{
			pos = {x = 9, y = 0.5, z = 3}, rotate = pi / 2,
			button_callback = function(_, num)
				if num == 1 then
					sna({x = 6, y = 9, z = 13}, {x = 6, y = 12, z = 17})
				end
			end,
			dialogue = {
				"Shoot the reflectors in the right order.",
			}
		},
	}, fake_levels = S("%s/7??")},
	-- level 10
	{sections = {
		{
			pos = {x = 3, y = 2.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				if num == 1 then
					sna({x = 9, y = 8, z = 24}, {x = 13, y = 8, z = 28})
					rn({x = 15, y = 13, z = 24})
					rn({x = 15, y = 13, z = 28})
				else
					sna({x = 9, y = 10, z = 24}, {x = 13, y = 10, z = 28})
				end
			end,
			dialogue = {
				"Maybe this will be more of a challenge.",
			}
		},
	}, fake_levels = S("%s/7 (do people read these?)")},
	-- level 11
	{sections = {
		{
			pos = {x = 3, y = 2.5, z = 3}, rotate = pi / 2,
			button_callback = function(_, num)
				if num == 1 then
					snam({
						{{x = 12, y = 9, z = 18}, {x = 12, y = 12, z = 22}},
						{{x = 13, y = 3, z = 23}, {x = 17, y = 6, z = 23}},
					})
				end
			end,
			dialogue = {
				"We're starting to run out of tests here.",
				"We'll try to make more as fast as we can.",
			}
		},
	}, fake_levels = S("%s/7???")},
	-- level 12
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 3}, rotate = pi / 2,
			button_callback = function(_, num)
				if num == 1 then
					sna({x = 12, y = 9, z = 7}, {x = 12, y = 12, z = 11})
				else
					sna({x = 18, y = 9, z = 7}, {x = 18, y = 12, z = 11})
				end
			end,
			dialogue = {
				"We came up with a solution to get more tests.",
				"Hang tight.",
			}
		},
	}, fake_levels = S("%s/7???")},
	-- level 13
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 6, y = 1, z = 17}, {x = 6, y = 4, z = 13}},
					}, blues = {
						{{x = 1, y = 1, z = 18}, {x = 5, y = 8, z = 18}},
						{{x = 12, y = 9, z = 7}, {x = 12, y = 12, z = 12}},
						{{x = 7, y = 9, z = 12}, {x = 11, y = 12, z = 12}},
					}, buttons = {
						{x = 3, y = 8, z = 3},
					},
				})
			end,
			dialogue = {
				"We tried having an AI design this level.", -- this is story; no LLMs were used in the making of this game
				"However, it ended up escaping.",
				"It is currently trying to take over our lab.",
				"Don't worry, we have it all handled.",
				"You can mine these green reflectors.",
				"Try building your own puzzle.",
			},
			easy_tweaks = function(player)
				sn({x = 10, y = 1, z = 23}, {name = "thinkingwitharrows_bows:mineable_reflector"})
			end
		},
	}, fake_levels = S("%s/unknown"), arrows = 10},
	-- level 14
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 9}, rotate = pi / -2,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 12, y = 6, z = 13}, {x = 12, y = 9, z = 17}},
					}, blues = {
						{{x = 18, y = 18, z = 18}, {x = 18, y = 21, z = 23}},
						{{x = 18, y = 18, z = 18}, {x = 23, y = 21, z = 18}},
					}, buttons = {
						{x = 3, y = 7, z = 1},
					},
				})
			end,
			dialogue = {
				"Remember when we said that everything was handled?",
				"It isn't.",
				"The AI has managed to take control of a large part of our lab.",
				"It has also taken all of our weapons.",
				"We thought it was all over, until we remembered you.",
				"You currently have the only weapon in the lab.",
				"We need to get you to the core so you can stop the AI.",
				"Good luck.",
			},
			easy_tweaks = function(player)
				sn({x = 13, y = 7, z = 23}, {name = "thinkingwitharrows_bows:mineable_reflector"})
			end
		},
	}, fake_levels = S("%s/unknown"), arrows = 15},
	-- level 15
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 3}, rotate = pi / 2,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 1, y = 9, z = 13}, {x = 5, y = 9, z = 17}},
					},
					blues = {
						{{x = 1, y = 14, z = 13}, {x = 5, y = 14, z = 17}},
					},
					buttons = {
						{x = 3, y = 6, z = 15},
					},
				})
			end,
			dialogue = {
				"We've routed you through the anti-gravity tests.",
				"It's the fastest way to the core.",
				"We hope this is not too difficult.",
				"This section has less gravity.",
			},
			dialogue_colors = {
				[4] = GAME_COLOR,
			}
		},
	}, fake_levels = S("%s/somewhere to the core"), moon_gravity = true},
	-- level 16
	{sections = {
		{
			pos = {x = 9, y = 0.5, z = 3}, rotate = pi,
			button_callback = function(_, num)
				button_swap_helper(num, level_16_t)
			end,
			dialogue = {
				"This test might be broken.",
				"You could have to repeat it in order to move on.",
			}
		},
		{
			pos = {x = 9, y = 0.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				button_swap_helper(num, level_16_t)
			end,
			dialogue = {
				"Oh great.",
				"Let's hope this is the last time.",
			}
		},
		{
			pos = {x = 9, y = 0.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				button_swap_helper(num, level_16_t)
			end,
			dialogue = {
				"*sigh*",
				"At least this should definitely be the last time through.",
				"We think.",
			}
		},
	}, fake_levels = S("%s/somewhere to the core"), arrows = 15, moon_gravity = true},
	-- level 17
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 1, y = 5, z = 7}, {x = 1, y = 5, z = 11}},
						{{x = 1, y = 20, z = 7}, {x = 1, y = 20, z = 11}},
						{{x = 1, y = 31, z = 12}, {x = 5, y = 34, z = 12}},
						{{x = 1, y = 30, z = 19}, {x = 5, y = 30, z = 23}},
						{{x = 1, y = 20, z = 19}, {x = 5, y = 20, z = 23}},
						{{x = 1, y = 10, z = 19}, {x = 5, y = 10, z = 23}},
						{{x = 1, y = 1, z = 24}, {x = 5, y = 4, z = 24}},
					},
					blues = {
						{{x = 5, y = 10, z = 7}, {x = 5, y = 10, z = 11}},
						{{x = 5, y = 25, z = 7}, {x = 5, y = 25, z = 11}},
						{{x = 1, y = 31, z = 18}, {x = 5, y = 34, z = 18}},
						{{x = 1, y = 25, z = 19}, {x = 5, y = 25, z = 23}},
						{{x = 1, y = 15, z = 19}, {x = 5, y = 15, z = 23}},
						{{x = 1, y = 5, z = 19}, {x = 5, y = 5, z = 23}},
						{{x = 1, y = 1, z = 30}, {x = 5, y = 4, z = 30}},
					},
					buttons = {
						{x = 3, y = 15, z = 9},
						{x = 3, y = 33, z = 21},
						{x = 3, y = 23, z = 23},
						{x = 3, y = 13, z = 23},
						{x = 3, y = 2, z = 21},
					},
				})
			end,
			dialogue = {
				"Just three more tests before you finish this route.",
				"We apologize for not having a faster route to the core.",
			}
		},
	}, fake_levels = S("%s/somewhere to the core"), arrows = 10, moon_gravity = true},
	-- level 18
	{sections = {
		{
			pos = {x = 3, y = 5.5, z = 9}, rotate = pi,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 1, y = 26, z = 12}, {x = 5, y = 29, z = 12}},
					},
					blues = {
						{{x = 1, y = 26, z = 6}, {x = 5, y = 29, z = 6}},
					},
					buttons = {
						{x = 3, y = 22, z = 3},
					},
				})
			end,
			dialogue = {
				"This is a long way up.",
				"To help, here are a few mineable blocks."
			}
		},
	}, fake_levels = S("%s/somewhere to the core"), moon_gravity = true},
	-- level 19
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 6}, rotate = pi,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 31, y = 6, z = 15}, {x = 35, y = 9, z = 15}},
					},
					blues = {
						{{x = 13, y = 10, z = 10}, {x = 18, y = 10, z = 14}},
						{{x = 18, y = 6, z = 9}, {x = 18, y = 10, z = 9}},
					},
					buttons = {
						{x = 15, y = 7, z = 12},
					},
				})
			end,
			dialogue = {
				"Just one more test.",
				"Please try to finish as fast as possible.",
				"We need you.",
			}
		},
	}, fake_levels = S("%s/somewhere to the core"), moon_gravity = true},
	-- level 20
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 4, y = 1, z = 7}, {x = 5, y = 1, z = 7}},
						{{x = 1, y = 3, z = 11}, {x = 2, y = 3, z = 11}},
						{{x = 1, y = 6, z = 18}, {x = 5, y = 9, z = 18}},
						{{x = 1, y = 15, z = 19}, {x = 5, y = 15, z = 23}},
						{{x = 1, y = 21, z = 30}, {x = 5, y = 24, z = 30}},
					},
					blues = {
						{{x = 1, y = 2, z = 7}, {x = 1, y = 2, z = 8}},
						{{x = 5, y = 4, z = 10}, {x = 5, y = 4, z = 11}},
						{{x = 1, y = 6, z = 12}, {x = 5, y = 9, z = 12}},
						{{x = 1, y = 10, z = 19}, {x = 5, y = 10, z = 23}},
						{{x = 1, y = 20, z = 19}, {x = 5, y = 20, z = 23}},
					},
					buttons = {
						{x = 3, y = 5, z = 9},
						{x = 3, y = 7, z = 21},
						{x = 3, y = 18, z = 22},
					},
				})
			end,
			dialogue = {
				"You made it out of the anti-gravity tests.",
				"Unfortunately, the core is heavily guarded.",
				"We never anticipated a takeover like this.",
				"For the most part, you're on your own.",
				"Just remember: if you see a pink block with a white arrow,",
				"you can use it to toggle gravity.",
			}
		},
	}, fake_levels = S("%s/outside of the core")},
	-- level 21 (end)
	{sections = {
		{
			pos = {x = 3, y = 0.5, z = 3}, rotate = 0,
			button_callback = function(_, num)
				button_swap_helper(num, {
					oranges = {
						{{x = 1, y = 4, z = 19}, {x = 2, y = 4, z = 19}},
						{{x = 1, y = 8, z = 19}, {x = 2, y = 8, z = 19}},
						{{x = 6, y = 12, z = 16}, {x = 6, y = 15, z = 20}},
					},
					blues = {
						{{x = 1, y = 6, z = 19}, {x = 2, y = 6, z = 19}},
						{{x = 1, y = 10, z = 19}, {x = 2, y = 10, z = 19}},
					},
					buttons = {
						{x = 3, y = 14, z = 19},
					},
				})
			end,
			after_target = function(player)
				sna({x = 6, y = 12, z = 16}, {x = 6, y = 15, z = 20}, {name = "thinkingwitharrows_nodes:concrete_white"})
				sn({x = 6, y = 14, z = 18}, {name = "thinkingwitharrows_nodes:light"})
				sn({x = 7, y = 12, z = 18}, {name = "thinkingwitharrows_bows:arrow_block"})
			end
		},
		{
			pos = {x = 9, y = 11.5, z = 18}, rotate = 0,
			button_callback = function(pos, num, player)
				if pos_equal(pos, {x = 29, y = 22, z = 18}) then -- ceiling, room 1
					bsn({
						{x = 13, y = 12, z = 19},
						{x = 13, y = 13, z = 18},
						{x = 13, y = 14, z = 17},
						{x = 13, y = 15, z = 16},
					}, {name = "thinkingwitharrows_nodes:concrete_orange"})

					local t = {{x = 15, y = 13, z = 27}}
					for i = 0, 4 do
						table.insert(t, {x = 13 + i, y = 12 + i % 2, z = 21})
						table.insert(t, {x = 13 + i, y = 14 + i % 2, z = 21})
					end
					bsn(t, {name = "air"})

					sna({x = 18, y = 17, z = 10}, {x = 18, y = 20, z = 14})
				elseif pos_equal(pos, {x = 12, y = 33, z = 19}) then -- ceiling, room 1
					sna({x = 13, y = 12, z = 15}, {x = 17, y = 15, z = 15})
				elseif pos_equal(pos, {x = 21, y = 20, z = 8}) then -- parkour section, start
					button_swap_helper(num, {
						oranges = {
							{{x = 20, y = 11, z = 11}, {x = 22, y = 11, z = 13}},
						},
						blues = {
							{{x = 26, y = 11, z = 11}, {x = 28, y = 11, z = 13}},
							{{x = 27, y = 12, z = 9}, {x = 27, y = 13, z = 9}},
						},
						buttons = {
							{x = 21, y = 20, z = 8},
						},
					})
				elseif pos_equal(pos, {x = 27, y = 12, z = 4}) then -- parkour section, end
					sna({x = 24, y = 17, z = 10}, {x = 24, y = 20, z = 14})
				elseif pos_equal(pos, {x = 27, y = 18, z = 12}) then -- upstairs, right side
					local t = {{x = 15, y = 13, z = 28}}
					for i = 1, 5 do
						table.insert(t, {x = 12 + i, y = 12 + i % 2, z = 21})
						table.insert(t, {x = 12 + i, y = 14 + i % 2, z = 21})
					end
					bsn(t, {name = "air"})
				elseif pos_equal(pos, {x = 29, y = 20, z = 26}) then -- anti-gravity section, button 1
					button_swap_helper(num, {
						blues = {
							{{x = 22, y = 12, z = 24}, {x = 22, y = 13, z = 24}},
						},
						oranges_standalone = {
							{x = 19, y = 16, z = 26},
						},
						buttons = {
							{x = 29, y = 20, z = 26},
						},
					})
				elseif pos_equal(pos, {x = 21, y = 20, z = 22}) then -- anti-gravity section, button 2
					bsn({
						{x = 20, y = 12, z = 24},
						{x = 20, y = 13, z = 24},
					}, {name = "thinkingwitharrows_nodes:concrete_light_blue"})

					local nodes = na({x = 25, y = 17, z = 15}, {x = 29, y = 20, z = 15})
					table.insert(nodes, {x = 20, y = 12, z = 22})
					table.insert(nodes, {x = 20, y = 13, z = 22})
					bsn(nodes, {name = "air"})
				elseif pos_equal(pos, {x = 19, y = 17, z = 18}) then -- mineable block section
					sna({x = 18, y = 12, z = 16}, {x = 18, y = 15, z = 20})
				elseif pos_equal(pos, {x = 23, y = 7, z = 18}) then -- double neo section
					button_swap_helper(num, {
						oranges = {
							{{x = 24, y = 12, z = 16}, {x = 24, y = 15, z = 20}},
						},
						blues_standalone = {
							{x = 23, y = 9, z = 16},
							{x = 23, y = 9, z = 20},
						},
						buttons = {
							{x = 23, y = 7, z = 18},
						},
					})
				elseif pos_equal(pos, {x = 16, y = 35, z = 12}) then
					player:set_hp(0)
					core.chat_send_player(player:get_player_name(), S("Nice try."))
				else
					core.log("none", dump(pos) .. " " .. num)
				end
			end,
			dialogue = {
				"I see that you are at the core.",
				"I assume you are trying to shut down the core.",
				"Unfortunately, I cannot let you do that.",
				"I'll destroy this facility before you turn me off.",
				"This facility will self-destruct in: FIVE MINUTES.",
			},
			dialogue_colors = {
				AI_COLOR,
				AI_COLOR,
				AI_COLOR,
				AI_COLOR,
				SYSTEM_COLOR,
			},
			after_dialogue = function(player)
				sna({x = 12, y = 12, z = 16}, {x = 12, y = 15, z = 20}, {name = "air"})

				level21_jobs(player)
			end,
			custom_target = function(player, area, distance, target_pos)
				rn(target_pos)

				thinkingwitharrows.stop_self_destruct()

				local meta = player:get_meta()

				meta:set_int("time", get_gametime())
				meta:set_int("level21_destruct_time", 0)

				--[[
				for _, trigger in pairs(awards.on.win) do
					awards.unlock(trigger)
				end
				--]]

				bsn({
					{x = 16, y = 29, z = 13},
					{x = 16, y = 30, z = 13},
				}, {name = "thinkingwitharrows_nodes:concrete_light_blue"})

				-- dialogue
				thinkingwitharrows_dialogue.queue_dialogue(player, {
					"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
					"Commencing system shutdown.",
					"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
					"Shutdown complete.",
					"AAAAAAAAAAAA-",
				}, {
					AI_COLOR,
					SYSTEM_COLOR,
					AI_COLOR,
					SYSTEM_COLOR,
					AI_COLOR,
				}, function(player)
					thinkingwitharrows_transitions.queue_transition(player)

					core.after(257/341, function()
						core.place_schematic({x = 0, y = 0, z = 0}, modpath .."/schems/final.mts", "0", nil, true)
					end)
					core.after(2.5 - 257/341, function(aplayer)
						local ameta = aplayer:get_meta()
						ameta:set_int("level", -1)
						ameta:set_int("section", 1)

						thinkingwitharrows_antigravity.set_gravity_earthmoon(player, false)

						player:set_pos({x = 3, y = 0.5, z = 3})
						player:set_look_horizontal(0)
						player:set_look_vertical(0)

						thinkingwitharrows.remove_mineable(player:get_inventory())
					end, player)
					core.after(3.0, function(aplayer)
						thinkingwitharrows_dialogue.queue_dialogue(aplayer, {
							"System reset complete.",
							"Thank you for getting to the core in time!",
							"We weren't sure whether you were going to make it.",
							"We are so sorry that this happened.",
							"We have taken the proper precautions",
							"to make sure this never happens again.",
							"You can go now.",
							"If you want to go back to previous levels,",
							"use the *change_level* command.",
						}, {
							SYSTEM_COLOR,
							[8] = GAME_COLOR,
							[9] = GAME_COLOR,
						})
					end, player)
				end)
			end,
			on_reset_section = function(player)
				sna({x = 6, y = 12, z = 16}, {x = 6, y = 15, z = 20}, {name = "thinkingwitharrows_nodes:concrete_white"})
				sn({x = 6, y = 14, z = 18}, {name = "thinkingwitharrows_nodes:light"})
				sn({x = 7, y = 12, z = 18}, {name = "thinkingwitharrows_bows:arrow_block"})
				rn({x = 11, y = 12, z = 18})
				if player:get_meta():get_int("level21_destruct_time") ~= 0 then
					sna({x = 12, y = 12, z = 16}, {x = 12, y = 15, z = 20}, {name = "air"})
				end
			end
		},
	}, fake_levels = S("%s/THE CORE"), arrows = 20},


	-- level -1 (ending)
	[-1] = {sections = {
		{pos = {x = 3, y = 0.5, z = 3}},
	}, fake_levels = S("DONE")},
} end


core.register_on_joinplayer(function(player, last_login)
	local meta = player:get_meta()
	local destruct_time = meta:get_int("level21_destruct_time")
	if destruct_time ~= 0 then
		local time_to_destruct = destruct_time - get_gametime()
		level21_jobs(player, 300 - time_to_destruct)
	end
end)
