tutorial = {}

-- == DEBUG SETTINGS ==
-- If true, item spawner nodes become visible and pointable.
local edit_item_spawners = minetest.settings:get_bool("tutorial_debug_edit_item_spawners")

-- See tutorial_mapgen/init.lua
local map_editing = minetest.settings:get_bool("tutorial_debug_map_editing")
if map_editing then
	minetest.settings:set_bool("creative_mode", true)
end

-- == END OF DEBUG SETTINGS ==

local S = minetest.get_translator("tutorial")
local NS = function(s) return s end

-- Saves tutorial state into file
function tutorial.save_state()
	local str = minetest.serialize(tutorial.state)
	local filepath = minetest.get_worldpath().."/tutorialdata.mt"
	local file = io.open(filepath, "w+")
	if(file) then
		file:write(str)
		minetest.log("action", "[tutorial] Tutorial state has been written into "..filepath..".")
	else
		minetest.log("error", "[tutorial] An attempt to save the tutorial state into "..filepath.." failed.")
	end
	io.close(file)
end


-- load tutorial state from file

local filepath = minetest.get_worldpath().."/tutorialdata.mt"
local file = io.open(filepath, "r")
local read = false
if file then
	local string = file:read()
	io.close(file)
	if(string ~= nil) then
		tutorial.state = minetest.deserialize(string)
		minetest.log("action", "[tutorial] Tutorial state has been read from "..filepath..".")
		read = true
	end
end
if(read==false) then
	tutorial.state = {}

	-- Is this the first time the player joins this tutorial? (used for spawn position)
	tutorial.state.first_join = true
	-- Has the regular introduction text been shown yet?
	tutorial.state.intro_text = false
	-- These variables store wheather a message for those events has been shown yet.
	tutorial.state.first_gold = false
	tutorial.state.last_gold = false
	tutorial.state.first_diamond = false
	tutorial.state.last_diamond = false
end

local function text_box(caption, text)
	return "label[0,-0.3;"..minetest.formspec_escape(S(caption)).."]"..
	"box[-0.05,0.25;12,5.2;#000000FF]"..
	"textarea[0.35,0.35;12,5.75;;;"..
	minetest.formspec_escape(S(text))..
	"]"
end

function tutorial.register_infosign(itemstringpart, caption, fulltext)
	tutorial.captions[itemstringpart] = caption
	minetest.register_node("tutorial:sign_"..itemstringpart, {
		description = S("tutorial sign '@1'", S(caption)),
		drawtype = "signlike",
		tiles = {"default_sign_wall.png"},
		inventory_image = "default_sign_wall.png",
		wield_image = "default_sign_wall.png",
		paramtype = "light",
		paramtype2 = "wallmounted",
		sunlight_propagates = true,
		is_ground_content = false,
		walkable = false,
		selection_box = { type = "wallmounted" },
		groups = {creative_breakable=1,attached_node=1,tutorial_sign=1},
		legacy_wallmounted = true,
		sounds = default.node_sound_defaults(),
		on_construct = function(pos)
			local meta = minetest.get_meta(pos)
			local formspec = ""..
			"size[12,6]"..
			"label[-0.15,-0.4;"..minetest.formspec_escape(S(caption)).."]"..
			"box[-0.05,0.25;12,5.7;#000000FF]"..
			"textarea[0.35,0.35;12,5.7;;;"..
			minetest.formspec_escape(S(fulltext))..
			"]"..
			"button_exit[4.5,5.5;3,1;close;"..minetest.formspec_escape(S("Close")).."]"
			meta:set_string("formspec", formspec)
			meta:set_string("infotext", S("@1 (Right-click to read)", S(caption)))
			meta:set_string("id", itemstringpart)
			meta:set_string("caption", caption)
		end
	})
end

minetest.register_abm( {
	nodenames = {"group:tutorial_sign"},
	interval = 1,
	chance = 1,
	action = function(pos, node, active_object_count, active_object_count_wider)
		local meta = minetest.get_meta(pos)
		local id = meta:get_string("id")
		local caption = tutorial.captions[id]
		if id == "" then
			return
		end
		local formspec = ""..
			"size[12,6]"..
			text_box(caption, tutorial.texts[id])..
			"button_exit[4.5,5.5;3,1;close;"..minetest.formspec_escape(S("Close")).."]"
			meta:set_string("formspec", formspec)
			meta:set_string("infotext", S("@1 (Right-click to read)", S(caption)))

	end }
)


-- Number of gold ingots/lumps
tutorial.gold = 13

-- Number of hidden diamonds
tutorial.diamonds = 12



tutorial.texts = {}

tutorial.texts.mobile =
NS[[PLEASE NOTE: Luanti can be played both on PC and mobile devices,
but this tutorial assumes you have a mouse and keyboard.

If you don't have those, the keys mentioned in this tutorial won't
make a lot of sense to you.

Do you want to proceed anyway?]]

tutorial.texts.intro =
NS[[Welcome! This tutorial will teach you the most crucial basics of Luanti.
This tutorial assumes that you have not changed the default keybindings yet.

Let's start for the most important keybindings right now:

   Look around: Move the mouse
   Walk forwards: [W]
   Strafe left: [A]
   Walk backwards: [S]
   Strafe right: [D]
   Action: [Right mouse button]
  Pause menu (you can exit the game here): [Esc]

You will find signs with more introductionary texts throughout this tutorial.
The "action" key has many uses. For now, let's just say you need it to read
the signs. Look at one and right-click it to read it.

To look at a sign, make sure you are close enough to it and the crosshair in the
center of the screen points directly on the sign.

You can exit the tutorial at any time, the world will be automatically saved.

Now feel free to walk around a bit and read the other signs to learn more.]]

tutorial.texts.minetest =
NS[[Luanti itself is not a game, it is a game engine.
To be able to actually play it, you need something called a "game".

This tutorial teaches you the basics of Luanti (the engine), things which are true for
all games. This tutorial does not teach you how to play a particular game.]]

tutorial.texts.subgame =
NS[[Now since you probably now the basics, you may want to actually play or build something.

You can check out one of the many games the community made in the ContentDB.
You can find it in the main menu under the "Content" tab or alternatively in
the web under <https://content.luanti.org>.]]


tutorial.texts.creative =
NS[[The creative mode is turned on. If you are here to learn how to play Luanti,
you should probably leave now, turn creative mode off and restart the
tutorial.

Roughly spoken, creative mode is for messing around with the game without
the normal gameplay restraints.

You can leave now by pressing "Leave tutorial", or later, by pressing [Esc].]]

tutorial.texts.notsingleplayer =
NS[[You are now playing the tutorial in multiplayer mode.
But this tutorial is optimized for the singleplayer mode.
This tutorial does not work properly with more than 1 player.

Unless you are sure no other players will join, you should
leave now and start the tutorial in singleplayer mode.]]

tutorial.texts.cam =
NS[=[Luanti has 3 different views which determine the way you see the world.
The three modes are:

- First-person view (default)
- Third-person view from behind
- Third-person view from the front

You can change the camera mode by pressing [C] (but you have to close this
window first).

   Switch camera mode: [C]]=]

tutorial.texts.minimap =
NS[=[Press the [V] key to make a minimap appear on the top right.
The minimap helps you to find your way around the world.
Press it again to toggle through different minimap modes and zoom levels.

Surface mode is a top-down view of the world, roughly resembling the
colors of the blocks this world is made on. It only shows the topmost
blocks, everything below is hidden, like a satellite photo. Surface
mode is useful if you got lost.

Radar mode is more complicated. It displays the "denseness" of the area
around you and changes with your height. Roughly, the more green an
area is, the less "dense" it is. Black areas have many blocks. Use
the radar to find caverns, hidden areas, walls and more.

There are also two different direction modes. Normally, "up" on the minimap
is always pointing to the North. But if you press [Shift]+[V], the minimap
will instead rotate with your looking direction, so "up" is always your
looking direction.

In some games, the minimap may be disabled.

   Toggle minimap mode: [V]
   Toggle minimap rotating: [Shift]+[V]]=]

tutorial.texts.blocks =
NS[[The world of Luanti is made entirely out of blocks, or voxels, to be precise.
Blocks can be added or removed with the correct tools.

In this section, we'll show you a few special but common blocks which behave in unexpected,
ways.,

Of course, games can come up with more special weird blocks.]]

tutorial.texts.falling_node =
NS[[Some blocks need to rest on top of another block, otherwise, they fall down.
Try it and mine the block below the uppermost block.]]

tutorial.texts.attached_node =
NS[[Some blocks have to be attached to another block, otherwise, they drop as an item
as if you would have mined it.

Attached here is a picture frame. You can't collect or mine it directly, but if you mine
the block it is attached to, it will drop as an item which you can collect.]]

tutorial.texts.disable_jump =
NS[[These nasty blocks on the floor prevent you from jumping when you stand on them.]]

tutorial.texts.bouncy =
NS[[Whee! The blocks will make you bounce if you jump on them. They also can bounce
you from the side, if you are fast enough.]]

tutorial.texts.runover =
NS[[This abyss behind this sign is so small that you can even walk over it,
as long as you don't stop midway. But you can jump over it anyways, just to be,
safe.]]

tutorial.texts.jumpup =
NS[[You can't reach this upper block by walking. But luckily, you are able to jump.
For our purposes, you can jump just high enough to reach one block above you.
But you can't two blocks high.
Press the space bar once to jump at a constant height.

   Jump: [Space]

Now try it to continue.]]


tutorial.texts.jumpover =
NS[=[Here is a slightly larger abyss. Luckily, you can also jump just far enough to
cross a gap of this width. Don't worry, the abyss is not deep enough to hurt you
when you fall down. There are stairs which lead back up here.

   Jump: [Space]]=]

tutorial.texts.orientation =
NS[[From this point on, there will be branching paths. For orientation, we placed
some arrow signs. They just show a short text when you hover them, that's all.

You don't have to follow the sections in any particular order, with one exception,
for which you will be informed.]]

tutorial.texts.sneak =
NS[=[Sneaking is a special move. As long as you sneak, you walk slower, but you are
guaranteed to not accidentally fall off the edge of a block. This also allows you to
"lean over" in a sense.
To sneak, keep the sneak key pressed. As soon as you release the sneak key,
you walk at normal speed again. Be careful not releasing the sneak key when you
are at a ledge, you might fall!

   Sneak: [Shift]

Keep in mind that the [Shift] key is used for a large number of other things in Luanti.
Sneaking only works when you are not in a liquid, stand on solid ground and are not at a
ladder.

You may try out sneaking at this little blocky pyramid.]=]

tutorial.texts.hotbar =
NS[[At the bottom of the screen you see 8 squares. This is called the 'hotbar'.
The hotbar allows you to quickly access some items from your inventory.
In our case, the upper 8 slots in your inventory.
You can change the selected item with the mouse wheel, if you have one, or with the
number keys.

   Select previous item in hotbar: [Mouse wheel up]
   Select next item in hotbar: [Mouse wheel down]
   Select item #N in hotbar: the key with the number #N

The item you've selected is also the item you wield. This will be important later for
tools, mining, building, etc.]]


tutorial.texts.eat =
NS[[In this chest you find some comestibles. Comestibles are items which instantly
heal you when eaten. This removes the item from your inventory.
To eat one, select the comestible in your hotbar, then click the left mouse button.
Unlike other items, you cannot punch or attack while holding a comestible. To be able
to attack, you have to select something else.
Of course, this does not have to be the only way to heal you.

   Eat comestible: [Left mouse button]

Don't forget to take the gold ingot.]]

tutorial.texts.chest =
NS[[Treasure chests are a common sight in Luanti. They are actually not built-in
into the game.]]

tutorial.texts.damageblock =
NS[[Careful! These spikes hurt you when you stand inside, so don't walk into them.
Try to walk around and get the gold ingot.

They damage you every second you stand in them.

This is one of the many ways you can get hurt in Luanti.]]

tutorial.texts.ladder =
NS[[This is a ladder. Ladders help you to climb up great heights or to climb down safely.
To climb a ladder, go into the block occupied by the ladder and hold one of the
following keys:

   Climb up ladder: [Space]
   Climb down ladder: [Shift]

Note that sneaking and jumping do not work when you are at a ladder.]]

tutorial.texts.swim =
NS[[What you see here is a small swimming pool. You are able to swim and dive.
Diving usually costs you breath. While diving, 10 bubbles appear in the heads-up display.
These bubbles disappear over time while diving and when you are out of bubbles,
you slowly lose some health points. You have to back up to the surface from time to
time to restore the bubbles.

Movement in a liquid is slightly different than on solid ground:

   Swim forwards: [W]
   Swim backwards: [S]
   Swim leftwards: [A]
   Swim rightwards: [D]
   Swim upwards: [Space]
   Swim downwards: [Shift]

At the bottom of the pool lies a gold ingot. Try to get it!]]


tutorial.texts.dive =
NS[=[To get to the other side, you have to dive here. Don't worry, the tunnel is not
long. But don't stay too long in the water, or else you take damage.
At the bottom of the pool lies a gold ingot. Try to get it!

   Swim forwards: [W]
   Swim backwards: [S]
   Swim leftwards: [A]
   Swim rightwards: [D]
   Swim upwards: [Space]
   Swim downwards: [Shift]]=]

tutorial.texts.waterfall = ""..
NS[=[You can easily swim up this waterfall. Go into the water and hold the space bar until you're
at the top

   Swim forwards: [W]
   Swim backwards: [S]
   Swim leftwards: [A]
   Swim rightwards: [D]
   Swim upwards: [Space]
   Swim downwards: [Shift]]=]

tutorial.texts.liquidtypes =
NS[=[Liquids behave somewhat weirdly in Luanti. Actually, there are 2 kinds of liquids.
If you watched the waterfall closely, you may have noticed that there is a slight difference
between the water blocks that make the waterfall, and those up here in the basin.

Luanti distinguishes between liquid source and flowing liquid.

A liquid source block is always a full cube.
A flowing liquid block looks slightly different. Often, it is not a full cube, but has a more or less
triangular shape. Also, flowing liquids usually have an unique "flowing" animation, but this may
not be the case for all liquids.

Up in the basin, you see four rows of liquid sources, followed by one row of flowing
liquids, followed by the waterfall itself. The waterfall itself is solely made of flowing liquids.

Liquid sources generate flowing liquids around them. Liquid sources can also exist on their own.
Flowing liquids are not able to exist on their own. They have to originate from a liquid source.
If the liquid source is gone, or the way to one is blocked, the flowing liquid will slowly dry
out.

To the right of this sign is a special block. When used, it will block the liquid flow.
Use that block, being close enough and looking at it, and watch the waterfall dry out.

   Use something: [Right mouse button]]=]

tutorial.texts.viscosity =
NS[[Luanti mods can introduce various liquids which differ in their properties.
Probably the most important property is their viscosity. Here you have some
pools which differ in their viscosity. Feel free to try them out.]]

tutorial.texts.pointing1 =
NS[[An important general concept in Luanti is pointing. As mentioned earlier,
there is a crosshair in the center of the screen.

You can point several things in Luanti:

- Blocks
- Dropped items
- Other players
- Many other things

You can only point one thing at once, or nothing at all.
When you're pointing a block, it is surrounded by a thin wireframe or it will
be highlighted (you can change the style in your settings).
When you're pointing an object, animal or another player, your crosshair will
change its shape.

To point something, three conditions have to be met:
1. The thing in question must be pointable at all
2. Your crosshair must be exactly over the thing in question
3. You must be close enough to the thing

When a thing is pointed, you can do different stuff with it; e.g. collecting it,
punching it, building to it, etc. We come to all that later.

Now collect that apple from the small tree in front of this sign, and the gold bar.
To do that, you must point it and click with the left mouse button.]]


tutorial.texts.pointing2 =
NS[[The distance you need to point to things solely depends on the tool you carry.
Most tools share a default value but some tools may have a longer or shorter distance.

At the moment, your only "tool" is the hand. It was good enough to collect the apple
from the small tree.

Above this sign hang some apples, but you cannot reach them by normal means. At the
wall in front of this sign lies a special example tool which you can use to retrieve the apple
from afar.

To take the tool, point to it and click the left mouse button. Then select it with the
mouse wheel or the number keys. You will learn more about tools in a different section.]]

tutorial.texts.health =
NS[[Unless you have damage disabled, all players start with 20 hit points (HP), represented
by ten hearts in the heads-up display. One HP is represented by half a heart in this
tutorial, but the actual representation can vary from game to game.

You can take damage for the following reasons (including, but not limited to):
- Falling too deep
- Standing in a block which hurts you
- Attacks from other players
- Staying too long in a liquid

In this tutorial, you can regain health by eating a comestible. This is only an example,
mods and games may come with other mechanisms to heal you.

When you lose all your hit points, you die. Death is normally not really that bad in Luanti.
When you die, you will usually lose all your possessions. You are able to put yourself
into the world immediately again. This is called "respawning". Normally you appear at a
more or less random location.
In the tutorial you can die, too, but don't worry about that. You will
respawn at a special location you can't normally reach and keep all your posessions.
Games may introduce special events on a player's death.]]

tutorial.texts.death =
NS[[Oops! So it seems you just have died. Don't worry, you don't have lost any of your
possessions and you have been revived. You are still in Tutorial World at a different
location.

You have arrived at the so-called respawn location of Tutorial World. You will
always appear here after you died. This is called "respawning". In most worlds,
however, you will respawn in a slightly randomized location.

The tutorial uses a so-called fixed spawn point, so you respawn always at the same
spot. This is unusual for singleplayer worlds, but in online play, some servers
use fixed spawn points, too.

Under normal conditions you would have lost all or a part of your possessions or some
other bad thing would have happened to you. But not here, this is a tutorial.

To continue, just drop out at the end of that gangway. The drop is safe.]]




tutorial.texts.items =
NS[[Throughout your journey, you will probably collect many items. Once you collected
them, blocks are considered to be items, too.

Items can be stored in your inventory and selected with the hotbar (see the other signs).
You can wield any items; you can even punch with almost any item to hurt enemies.
Usually, you will deal a minimal default damage with most items. Even if you do not hold,
an item at all.
If you don't want to have an item anymore, you can always throw it away. Likewise,
you can collect items which lie around by pointing and leftclicking them.

   Collect item: [Left mouse button]
   Drop carried item stack: [Q]
   Drop single item from carried item stack: [Shift] + [Q]

On the table at the right to this sign lies an item stack of 50 rocks so you have some items,
to test out the inventory.]]

tutorial.texts.tools =
NS[[A tool is a special kind of item.
Tools can be used for many things, such as:
- Breaking blocks
- Collecting liquids
- Rotating blocks
- Many others!
The number of tools which are possible in Luanti is innumberable and are
too many to cover in this tutorial.
But at least we will look at a very common and important tool type: mining tools,
We will come to that in the mining section.

Many tools wear off and get destroyed after you used them for a while. In an
inventory the tool's "health" is indicated by a colored bar

Tools may be able to be repaired, see the sign about repairing.]]

tutorial.texts.inventory =
NS[[The inventory menu usually contains the player inventory. This allows you
to carry along items throughout the world.

Every inventory is made out of slots where you can store items in. You can store one
entire stack of items per slot, the only condition is that the items are of the same
type. In this tutorial all items except for tools stack up to 99 items, but this number
can vary in actual games.

Here are the controls which explain how to move around the items within the inventory:

In the game:
   Open inventory menu: [I]

When the inventory is opened and you don't hold any items:
   Take item stack: [Left mouse button]
   Take 10 items from item stack: [Middle mouse button]
   Take half item stack: [Right mouse button]

When you took an item stack in the inventory:
   Put item stack: [Left mouse button]
   Put 10 items from item stack: [Middle mouse button]
   Put single item from item stack: [Right mouse button]

You can also drop an item stack by holding it in the inventory, then clicking anywhere
outside of the window.]]

tutorial.texts.listrings =
NS[=[By the way, if you are tired of clicking, there is a little convenience
feature:
Hold [Shift] while you left-click on an item stack in a menu to
move it instantly to another relevant section. For example, in this tutorial
you can use it to move an item stack from the chest into your inventory (and
vice-versa) with a single click.

   [Shift]+[Left click]: Move full item stack to other section in menu]=]

tutorial.texts.chest =
NS[[This is a chest. You can view its contents by right-clicking it. In the menu you will see
two inventories, on the upper part the chest inventory and on the lower part the player
inventory. Exchanging items works exactly the same as in the inventory menu.]]


tutorial.texts.build =
NS[[Another important task in Luanti is building blocks.
"Building" here refers to the task of placing one block in your possession onto
another block in the world.
Unlike mining, building a block happens instantanous. To build, select a block in your
hotbar, point to any block in the world and press the right mouse button.
Your block will be immediately placed on the pointed side.
It is important that the block you want to build to is pointable. This means you cannot build
next to or on liquids by normal means.

   Build on ordinary block: [Right mouse button]

Try to get up to that little hole by using the wood blocks in the chest. There is another
gold ingot waiting for you.]]

tutorial.texts.build_special =
NS[=[You may have wondered how you can build on a block which you can use, like a chest.
For this, you have to hold the sneak key and then use the build key.

   Build on usable block: [Shift] + [Right mouse button]]=]

tutorial.texts.mine =
NS[[Mining is a method to remove a single block with a mining tool. It is a very important
task in Luanti which you will use often.

(It is recommended that you go to the crafting and items house first. It is right in front of
this sign.)

To be able to mine a block, you need

1. to have minable block, after all,
2. to point on the block and
3. to carry an appropriate tool.

   Mine: [Left mouse button]

When you are ready, hold the left mouse button while pointing the block. Depending on
the block type and the tool properties, this can take some time. Some tools are fast with
some particular block types, some other tools may be slower to mine other block types.
If you do not carry an appropriate tool, you are not able to mine the block at all.
You can tell that you are actually mining when you see cracks or some other animation
on the block in question.

When done mining, blocks will often add one or more items to your inventory. This is called
the "drop" of a block and depends on the block type. Now try to mine those large cubes in
this area, using different tools. Note that all blocks here are just examples to show you
different kinds of drops.]]

tutorial.texts.mine_cobble =
NS[[This is cobblestone. You can mine it with a pickaxe.
This cobblestone will always drop itself, that means, cobblestone. Dropping itself is the
usual dropping behaviour of a block, throughout many games.]]

tutorial.texts.mine_wood =
NS[[These are wooden planks. In the tutorial, you can only mine those blocks with an axe.
Wooden planks drop themselves.

In Luanti, we use the term "mining" in a general sense, regardless of the material.]]

tutorial.texts.mine_conglomerate =
NS[[This is a cube of conglomerate. You need a pickaxe to mine it.
Conglomerate drops something based on probability. Conglomerate randomly drops between 1
and 5 rocks, when mined.]]

tutorial.texts.mine_glass =
NS[[This is some weak glass. You can break it with your bare hands. Or you can use your pickaxe,
which is faster. Note that it looks slightly different than the other glass in this world.
These glass blocks don't drop anything.]]

tutorial.texts.mine_stone =
NS[[This is stone. You need a pickaxe to mine it. When mined, stone will drop cobblestone.]]

tutorial.texts.mine_immortal =
NS[[There can always be some blocks which are not minable by any tool. In our tutorial, all
those castle walls can't me mined, for example.]]

tutorial.texts.craft1 =
NS[[Crafting is the task of taking several items and combining them to form a new item.
Crafting is another important task in Luanti.

To craft something, you need a few items and a so-called crafting grid.

In this tutorial, you have a grid of size 3 times 3 in your inventory.
Let's get right into crafting:

1. Take 3 sheets of paper from the chest next to this sign.
2. Open the inventory menu with [I].
3. Place the paper in the crafting grid so that they form a 1×3 vertical line.
4. A book should appear in the output slot. Click on it to take it,
   then put it in your player inventory.

This process consumes the paper.
When you have the book in your inventory, go on with the next sign.]]

tutorial.texts.craft2 =
NS[[To craft the book you have used a so-called crafting recipe. You must know the crafting
recipes as well so you can craft.

The crafting recipe you used in particular is a so-called shaped recipe. This means the
pattern you place in the crafting grid matters, but you can move the entire pattern
freely.

There is another kind of crafting recipe: Shapeless.
Shapeless recipes only care about which items you place in the crafting grid, but not in
which pattern. In the next chest you find some wheat. Let's make dough from it! For this,
you have to place at least 1 wheat in 4 different slots, but the other slots must be empty.
What is special about this recipe is that you can place them anywhere in the grid.

When you got your dough, go on with the next sign.]]

tutorial.texts.craft3 =
NS[[Do you got your dough? Good.

You may have noticed that crafting always consumes one item from each occupied slot
of the crafting grid. This is true for all crafting recipes.
You can speed crafting up a bit when you click with the middle mouse button on the
item in the output slot. Doing so will attempt to do the same craft up to 10 times,
instead of just once.

Feel free to try it with the remaining wheat or just go on with the next sign.]]

tutorial.texts.craft4 =
NS[[Another important thing to know about crafting are so-called groups. Crafting recipes do
not always require you to use the exactly same items every time.
This tutorial has a special recipe for books. In the chest, you will find paper in 4
different colors. You can also make a book by placing 3 paper sheets of any color
in a vertical line.
The paper color does not matter here, you can use only white paper, only orange paper
or even mix it. What is important here are the occupied slots.
This is possible because all 4 types of (example) paper belong to the same group and
our book recipe accepts not only white paper, but any paper of that group.

Feel free to experiment a bit around with this.]]

tutorial.texts.smelt =
NS[[This is a furnace. Furnaces can be used to turn a smeltable item with help of a fuel
to a new item. Many items can be furnace fuels, but not all. A few items are smeltable.

In order to operate a furnace, you have to put the smeltable item into the 'Source' slot
and the fuel into the 'Fuel' slot.
As soon as the items have been placed, the furnace automatically starts to smelt the
items. The furnace becomes active and consumes an item in the fuel slot. The flame
goes on and will continue burning for a given time. The time depends on the fuel type.
Some fuels burn very short, and others burn longer. In the furnace menu, the burn time
is indicated by the flame symbol. As soon as the flame goes out, the furnace may
continue burning if there is still fuel and smeltable material in the furnace,
otherwise, the furnace becomes inactive again.
The smeltable material has to be exposed to the flame for a given time as well. This
time depends on the type of the material, too. Some material smelt faster than others.
You can see the smelting progress of a single item on the progress arrow. If one item
has been smelt, the result goes to one of the output slots, where you can take it.

In the left chest you find some fuels and in the right chest you find some materials to
smelt. Feel free to experiment with the furnace a bit. Smelt the gold lump to receive
this station's gold bar.

Again, this furnace is just an example; the exact operation may differ slightly from
game to game.]]

tutorial.texts.repair =
NS[[Some games may come with a special recipe which allows you to repair your tools.
In those, repairing works always the same way:
Place two more or less worn out tools of the same kind into the crafting crid and
take the result. The result is a new tool which is slightly repaired by a fixed percentage.

Of course, this tutorial comes with such a recipe. The chest next to this sign stores
some damaged tools which you may try to repair now.]]


tutorial.texts.use =
NS[=[You will often meet some blocks you can use. Something special happens when you
right-click while pointing on them.
In fact, you already used such blocks: All the signs you read are "usable" blocks.

There is a strange device next to this sign. Use it and see what happens.

   Use usable block: [Right mouse button]]=]


tutorial.texts.basic_end =
NS[[If you think you have enough of this tutorial, you can leave at any time. There are
13 gold ingots at the stations to be found, to help you keep track.

You can find the gold ingots at the following stations:
- Ladders
- Sneaking
- Swimming
- Diving
- Waterfall
- Viscosity
- Comestibles and Eating
- Pointing
- Crafting
- Smelting
- Mining
- Building
- Damage and Health

If you've got 13 gold ingots (in total), you probably know now everything which can be
learned from this tutorial. Collecting the gold ingots is optional.

After you closed this dialog, you can press [Esc] to open the pause menu and return
to the main menu or quit Luanti.

In the next room there are some further signs with information, but it is entirely optional
and not related to gameplay.]]

tutorial.texts.first_gold =
NS[[You have collected your first gold ingot. Those will help you to keep track in this tutorial.
There are 13 gold ingots in this tutorial.

There is a gold ingot at every important station. If you collected all ingots, you are
done with the tutorial, but collecting the gold ingots is not mandatory.]]

tutorial.texts.last_gold =
NS[[You have collected all the gold ingots in this tutorial.

This means you have now travelled to each station. If you read and understood everything,
you have learned everything which can be learned from this tutorial.

If this is the case, you are finished with this tutorial and can leave now. But feel
free to stay in this world to explore the area a bit further.

You may also want to visit the Good-Bye room, which has a few more informational
signs with supplemental information, but nothing of is is essential or gameplay-relevant.

If you want to stay, you leave later by pressing [Esc] to open the pause menu and then
return to the main menu or quit Luanti.]]

tutorial.texts.first_diamond =
NS[[Great, you have found and collected a hidden diamond! In Tutorial World, there are 12 hidden
diamonds. Can you find them all? The first diamond may have been easy to collect, but the
remaining 11 diamonds probably won't be that easy.

If you manage to find them all, you will be awarded a symbolic prize.]]

tutorial.texts.last_diamond =
NS[[Congratulations!
You have collected all the diamonds of Tutorial World!

To recognize this achievement, you have been awarded with a diamond cup. It has been placed in
the Good-Bye Room for you.]]


tutorial.texts.controls =
NS[[To recap, here is an overview over the most important default controls:

   Move forwards: [W]
   Move left: [A]
   Move backwards: [S]
   Move right: [D]
   Jump: [Space]
   Sneak: [Shift]
   Move upwards (ladder/liquid): [Space]
   Move downwards (ladder/liquid): [Shift]

   Toggle camera mode: [C]
   Toggle minimap mode: [V]

   Select item in hotbar: [Mouse wheel]
   Select item in hotbar: [0] - [9]
   Inventory menu: [I]

   Collect pointed item: [Left mouse button]
   Drop item stack: [Q]
   Drop single item: [Shift] + [Q]

   Punch: [Left mouse button]
   Mine: [Left mouse button]
   Build/use: [Right mouse button]
   Build: [Shift] + [Right mouse button]

   Abort/open pause menu: [Esc]

You can review a shorter version of the controls in the pause menu.]]


tutorial.texts.online =
NS[[You may want to check out these online resources related to Luanti:

Official homepage of Luanti: <https://luanti.org/>
The main place to find the most recent version of Luanti.

ContentDB: <https://content.luanti.org/>
Browse the community creations for Luanti: Games, mods and texture packs!

Community wiki: <https://wiki.luanti.org/>
A community-based documentation website for Luanti. Anyone with an account can edit
it!

Webforums: <https://forum.luanti.org/>
A web-based discussion platform where you can discuss everything related to Luanti.
This is also a place where player-made mods and games are published and
discussed. The discussions are mainly in English, but there is also space for
discussion in other languages.

Chat: <irc://irc.libera.chat#minetest>
A generic Internet Relay Chat channel for everything related to Luanti where people can
meet to discuss in real-time.
If you do not understand IRC, see the Community Wiki for help.]]

tutorial.captions = {}

tutorial.locations = {
	intro = { { x = 42, y = 0.5, z = 28 }, math.pi * 0.5 },
	jumpup = { { x = 64, y = 0.5, z = 30 }, math.pi * 1.5, math.pi * 0.2 },
	ladder = { { x = 70, y = 0.5, z = 37 }, math.pi * 0.5 },
	swim = { { x = 85, y = 0.5 , z = 50 }, math.pi * 0.5 },
	dive = { { x = 59, y = 0.5 , z = 62 }, math.pi * 0.5 },
	sneak = { { x = 33, y = 0.5, z = 41 }, math.pi * 0.5 },
	eat = { { x = 67, y = -3.5, z = 60}, 0 },
	health = { { x = 50, y = 0.5, z = 58 }, 0 },
	viscosity = { { x = 44, y = 0.5, z = 53 }, 0, math.pi * 0.2 },
	waterfall = { { x = 40, y = 0.5 , z = 81 }, 0 },
	pointing1 = { { x = 89, y = 0.5, z = 62 }, math.pi * 0.5 },
	items = { { x = 70, y = 0.5, z = 65 }, math.pi },
	craft1 = { { x = 74, y = 0.5, z = 59 }, math.pi * 1.5 },
	repair = { { x = 80, y = 0.5, z = 59 }, math.pi },
	smelt = { { x = 78, y = 4.5, z = 63 }, math.pi * 1.5 },
	mine = { { x = 79, y = 0.5, z = 75 }, 0, math.pi * 0.2 },
	build = { { x = 66, y = 0.5, z = 83 }, math.pi },
	goodbye = { { x = 22.5, y = 0.5, z = 73 }, math.pi * 0.5 },
}

tutorial.locations_order = {
	"intro", "jumpup", "pointing1", "items", "eat", "craft1", "repair", "smelt", "mine", "build", "swim", "dive", "viscosity", "waterfall", "health", "sneak", "goodbye"
}

tutorial.register_infosign("intro", NS"Introduction", tutorial.texts.intro)
tutorial.register_infosign("minetest", NS"Luanti", tutorial.texts.minetest)
tutorial.register_infosign("cam", NS"Player Camera", tutorial.texts.cam)
tutorial.register_infosign("minimap", NS"Minimap", tutorial.texts.minimap)
tutorial.register_infosign("runover", NS"Small Abysses", tutorial.texts.runover)
tutorial.register_infosign("jumpup", NS"Jumping (1)", tutorial.texts.jumpup)
tutorial.register_infosign("jumpover", NS"Jumping (2)", tutorial.texts.jumpover)
tutorial.register_infosign("sneak", NS"Sneaking", tutorial.texts.sneak)
tutorial.register_infosign("orientation", NS"Information about the following tutorial sections", tutorial.texts.orientation)
tutorial.register_infosign("hotbar", NS"Hotbar", tutorial.texts.hotbar)
tutorial.register_infosign("eat", NS"Comestibles and Eating", tutorial.texts.eat)
tutorial.register_infosign("chest", NS"Chests", tutorial.texts.chest)
tutorial.register_infosign("damageblock", NS"Blocks Which Hurt You", tutorial.texts.damageblock)
tutorial.register_infosign("ladder", NS"Climbing Ladders", tutorial.texts.ladder)
tutorial.register_infosign("swim", NS"Swimming", tutorial.texts.swim)
tutorial.register_infosign("dive", NS"Diving", tutorial.texts.dive)
tutorial.register_infosign("waterfall", NS"Swimming up a Waterfall", tutorial.texts.waterfall)
tutorial.register_infosign("viscosity", NS"Viscosity", tutorial.texts.viscosity)
tutorial.register_infosign("liquidtypes", NS"Liquid sources and flowing liquids", tutorial.texts.liquidtypes)
tutorial.register_infosign("pointing1", NS"Pointing (1)", tutorial.texts.pointing1)
tutorial.register_infosign("pointing2", NS"Pointing (2)", tutorial.texts.pointing2)
tutorial.register_infosign("health", NS"Health and Damage", tutorial.texts.health)
tutorial.register_infosign("death", NS"Death and Respawning", tutorial.texts.death)
tutorial.register_infosign("items", NS"Items", tutorial.texts.items)
tutorial.register_infosign("tools", NS"Tools", tutorial.texts.tools)
tutorial.register_infosign("inventory", NS"Using the Inventory", tutorial.texts.inventory)
tutorial.register_infosign("listrings", NS"Inventory shortcut", tutorial.texts.listrings)
tutorial.register_infosign("chest", NS"Comment About Chests", tutorial.texts.chest)
tutorial.register_infosign("build", NS"Building Some Blocks", tutorial.texts.build)
tutorial.register_infosign("build_special", NS"Building at Usable Blocks", tutorial.texts.build_special)
tutorial.register_infosign("mine", NS"Mining blocks", tutorial.texts.mine)
tutorial.register_infosign("mine_cobble", NS"Mining example: Cobblestone", tutorial.texts.mine_cobble)
tutorial.register_infosign("mine_stone", NS"Mining example: Stone", tutorial.texts.mine_stone)
tutorial.register_infosign("mine_conglomerate", NS"Mining example: Conglomerate", tutorial.texts.mine_conglomerate)
tutorial.register_infosign("mine_wood", NS"Mining example: Wooden Planks", tutorial.texts.mine_wood)
tutorial.register_infosign("mine_glass", NS"Mining example: Weak glass", tutorial.texts.mine_glass)
tutorial.register_infosign("mine_immortal", NS"Unminable blocks", tutorial.texts.mine_immortal)
tutorial.register_infosign("blocks", NS"Special blocks", tutorial.texts.blocks)
tutorial.register_infosign("disable_jump", NS"No-jumping blocks", tutorial.texts.disable_jump)
tutorial.register_infosign("bouncy", NS"Bouncy blocks", tutorial.texts.bouncy)
tutorial.register_infosign("falling_node", NS"Falling blocks", tutorial.texts.falling_node)
tutorial.register_infosign("attached_node", NS"Attached blocks", tutorial.texts.attached_node)
tutorial.register_infosign("use", NS"Using blocks", tutorial.texts.use)
tutorial.register_infosign("craft1", NS"Crafting Basics", tutorial.texts.craft1)
tutorial.register_infosign("craft2", NS"Crafting using Shapeless Recipes", tutorial.texts.craft2)
tutorial.register_infosign("craft3", NS"Crafting Faster", tutorial.texts.craft3)
tutorial.register_infosign("craft4", NS"Crafting Groups", tutorial.texts.craft4)
tutorial.register_infosign("smelt", NS"Furnace Operation Instructions", tutorial.texts.smelt)
tutorial.register_infosign("repair", NS"Repairing Tools", tutorial.texts.repair)
tutorial.register_infosign("basic_end", NS"End of the Basic Tutorial", tutorial.texts.basic_end)
tutorial.register_infosign("controls", NS"Controls Overview", tutorial.texts.controls)
tutorial.register_infosign("online", NS"Online Resources", tutorial.texts.online)
tutorial.register_infosign("subgame", NS"Games", tutorial.texts.subgame)

minetest.register_node("tutorial:wall", {
	description = S("reinforced wall"),
	tiles = {"default_stone_brick.png"},
	is_ground_content = true,
	groups = {creative_breakable=1},
	sounds = default.node_sound_stone_defaults(),
})

minetest.register_node("tutorial:wood", {
	description = S("reinforced wood"),
	tiles = {"default_wood.png"},
	groups = {creative_breakable=1},
	sounds = default.node_sound_wood_defaults(),
})

minetest.register_node("tutorial:reinforced_glass", {
	description = S("reinforced glass"),
	drawtype = "glasslike",
	tiles = {"tutorial_reinforced_glass.png"},
	inventory_image = minetest.inventorycube("tutorial_reinforced_glass.png"),
	paramtype = "light",
	sunlight_propagates = true,
	groups = { creative_breakable=1 },
	sounds = default.node_sound_glass_defaults(),
})

minetest.register_node("tutorial:weak_glass", {
	description = S("weak glass"),
	drawtype = "glasslike",
	tiles = {"tutorial_weak_glass.png"},
	inventory_image = minetest.inventorycube("tutorial_weak_glass.png"),
	paramtype = "light",
	sunlight_propagates = true,
	groups = { cracky=3, oddly_breakable_by_hand=1 },
	drop = "",
	sounds = default.node_sound_glass_defaults(),
})


minetest.register_tool("tutorial:snatcher", {
	description = S("apple snatcher"),
	inventory_image = "tutorial_snatcher.png",
	wield_image = "tutorial_snatcher.png",
	wield_scale = { x = 1, y = 1, z = 1 },
	range = 10,
	tool_capabilities = {},
})

--[[ A special switch which, when flipped, exchanges day for night and vice versa. ]]
minetest.register_node("tutorial:day", {
	description = S("day/night switch (day)"),
	tiles = { "tutorial_day.png" },
	groups = {creative_breakable=1},
	on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
		minetest.set_timeofday(0)
		minetest.set_node(pos, {name="tutorial:night"})
	end
})
minetest.register_node("tutorial:night", {
	description = S("day/night switch (night)"),
	tiles = { "tutorial_night.png" },
	groups = {creative_breakable=1},
	on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
		minetest.set_timeofday(0.5)
		minetest.set_node(pos, {name="tutorial:day"})
	end
})

--[[ A special switch which "activates" and "deactivates" the waterfall in Tutorial World.
It only works on a prepared map! ]]
minetest.register_node("tutorial:waterfall_on", {
	description = S("waterfall switch (on)"),
	tiles = { "tutorial_waterfall_on.png" },
	groups = {creative_breakable=1},
	on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
		local wpos = { y = 5, z = 86 }
		for x=33,46 do
			wpos.x = x
			minetest.set_node(wpos, {name="tutorial:wall"})
		end
		minetest.set_node({x=30,y=7,z=91}, {name="tutorial:waterfall_off"})
		minetest.set_node({x=40,y=2,z=86}, {name="tutorial:waterfall_off"})
	end
})
minetest.register_node("tutorial:waterfall_off", {
	description = S("waterfall switch (off)"),
	tiles = { "tutorial_waterfall_off.png" },
	groups = {creative_breakable=1},
	on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
		local wpos = { y = 5, z = 86 }
		for x=33,46 do
			wpos.x = x
			minetest.remove_node(wpos)
		end
		minetest.set_node({x=30,y=7,z=91}, {name="tutorial:waterfall_on"})
		minetest.set_node({x=40,y=2,z=86}, {name="tutorial:waterfall_on"})
	end
})

-- Ruler (used in sneaking section)
minetest.register_node("tutorial:ruler", {
	description = S("ruler"),
	drawtype = "signlike",
	selection_box = {
		type = "wallmounted",
		wall_side = { -0.5, -0.5, 1/16, -0.4, 0.5, 0.5 },
	},
	walkable = false,
	tiles = { "tutorial_ruler.png" },
	inventory_image = "tutorial_ruler.png",
	wield_image = "tutorial_ruler.png",
	paramtype = "light",
	paramtype2 = "wallmounted",
	sunlight_propagates = true,
	groups = {creative_breakable=1, attached_node=1},
})

local is_drawtype, is_pointable, is_diggable, is_air_equivalent, is_tiles
-- Make some changes to item spawner node if debug setting is active
if edit_item_spawners then
	-- This makes the item spawner visible and clickable
	is_drawtype = "glasslike"
	is_pointable = true
	is_diggable = true
	is_air_equivalent = false
	is_tiles = { "tutorial_item_spawner.png" }
else
	-- Normal invisible non-pointable non-editable item spawner
	is_drawtype = "airlike"
	is_pointable = false
	is_diggable = false
	is_air_equivalent = true
	is_tiles = nil
end

-- Item spawner
minetest.register_node("tutorial:itemspawner", {
	description = S("item spawner"),
	paramtype = "light",
	walkable = false,
	-- See above
	drawtype = is_drawtype,
	pointable = is_pointable,
	diggable = is_diggable,
	air_equivalent = is_air_equivalent,
	tiles = is_tiles,
	floodable = false,
	inventory_image = "tutorial_item_spawner.png",
	wield_image = "tutorial_item_spawner.png",
	buildable_to = false,
	sunlight_propagates = true,
	groups = {creative_breakable=1},
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_int("configged", 0)
		local formspec = ""..
		"size[12,6]"..
		"label[-0.15,-0.4;"..minetest.formspec_escape(S("Item spawner")).."]"..
		"field[0,1;10,1;offset;"..minetest.formspec_escape(S("Offset"))..";(0,0,0)]"..
		"field[0,2;10,1;itemstring;"..minetest.formspec_escape(S("Itemstring"))..";]"..
		"button_exit[4.5,5.5;3,1;close;"..minetest.formspec_escape(S("OK")).."]"
		meta:set_string("formspec", formspec)
		meta:set_string("infotext", S("Item spawner (inactive)"))
	end,
	on_receive_fields = function(pos, formname, fields, sender)
		if not fields.offset or fields.offset == "" then
			fields.offset = "(0,0,0)"
		end
		if fields.offset and fields.itemstring then
			local meta = minetest.get_meta(pos)
			meta:set_string("offset", fields.offset)
			meta:set_int("configged", 1)
			meta:set_string("itemstring", fields.itemstring)
			meta:set_string("formspec", "")
			meta:set_string("infotext", "")
		end
	end,
	on_timer = function(pos, elapsed)
		local meta = minetest.get_meta(pos)
		if meta:get_int("configged") == 0 or edit_item_spawners then
			return
		end

		local offset = minetest.string_to_pos(meta:get_string("offset"))
		local itemstring = meta:get_string("itemstring")
		local test_item = ItemStack(itemstring)
		local test_itemname = test_item:get_name()
		local alias = minetest.registered_aliases[test_itemname]
		local itemname
		if alias then
			test_item:set_name(alias)
			itemstring = test_item:to_string()
		end
		local x, y, z = offset.x, offset.y, offset.z
		local spawnpos = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
		local objs = minetest.get_objects_inside_radius(spawnpos, 1)
		for o=1, #objs do
			local ent = objs[o]:get_luaentity()
			if ent then
				local ent_itemstack = ItemStack(ent.itemstring)
				local itemstack = ItemStack(itemstring)
				if ent.name == "__builtin:item" and ent_itemstack:get_name() == itemstack:get_name() then
					-- Remove node when item was spawned successfully.
					-- So it doesn't get in the way.
					minetest.remove_node(pos)
					return
				end
			end
		end
		if itemstring ~= nil and itemstring ~= "" then
			minetest.add_item(spawnpos, itemstring)
			local timer = minetest.get_node_timer(pos)
			timer:start(1)
			return
		end

		local timer = minetest.get_node_timer(pos)
		timer:start(1)
	end,
})

-- Crafting guides (example crafting images at crafting section)
function tutorial.craftguideinfo(pos)
	local meta = minetest.get_meta(pos)
	meta:set_string("infotext", S("This is a crafting example."))
end

function tutorial.register_craftguide(subId, desc, imageStatic, imageAnim, animFrames)
	local id = "tutorial:craftguide_"..subId

	local tiles
	if imageAnim ~= nil then
		tiles = {
			{
				name = imageAnim,
				animation = {
					type = "vertical_frames",
					aspect_w = 32,
					aspect_h = 32,
					length = animFrames * 4.0,
				},
			}
		}
	else
		tiles = { imageStatic }
	end

	minetest.register_node(id, {
		description = desc,
		drawtype = "signlike",
		selection_box = {
			type = "wallmounted",
			wall_side = { -0.5, -0.5, -0.5, -0.4, 0.5, 0.5 },
		},
		walkable = false,
		tiles = tiles,
	inventory_image = imageStatic,
		wield_image = imageStatic,
		paramtype = "light",
		paramtype2 = "wallmounted",
		sunlight_propagates = true,
		groups = {creative_breakable=1, attached_node=1},
		on_construct = tutorial.craftguideinfo,
	})

	minetest.register_abm({
		nodenames = id,
		interval = 5,
		chance = 1,
		action = tutorial.craftguideinfo,
	})
end

tutorial.register_craftguide("paper", S("crafting example: white paper"), "tutorial_craftguide_paper_white.png")
tutorial.register_craftguide("wheat", S("crafting example: wheat"), "tutorial_craftguide_wheat.png", "tutorial_craftguide_wheat_anim.png", 3)
tutorial.register_craftguide("paper_color", S("crafting example: colored paper"), "tutorial_craftguide_paper_color.png", "tutorial_craftguide_paper_color_anim.png", 4)
tutorial.register_craftguide("repair", S("crafting example: tool repair"), "tutorial_craftguide_repair.png", "tutorial_craftguide_repair_anim.png", 3)

--[[ Tutorial cups, awarded for achievements ]]
tutorial.cupnodebox = {
	type = "fixed",
	fixed = {
		{-0.3,-0.5,-0.3,0.3,-0.4,0.3}, -- stand
		{-0.1,-0.4,-0.1,0.1,0,0.1}, -- handle
		{-0.3,0,-0.3,0.3,0.1,0.3}, -- cup (lower part)
		-- the 4 sides of the upper part
		{-0.2,0.1,-0.3,0.2,0.5,-0.2},
		{-0.2,0.1,0.2,0.2,0.5,0.3},
		{-0.3,0.1,-0.3,-0.2,0.5,0.3},
		{0.2,0.1,-0.3,0.3,0.5,0.3},
	}
}

tutorial.cupselbox = {
	type = "fixed",
	fixed = {
		{-0.3,-0.5,-0.3,0.3,-0.4,0.3}, -- stand
		{-0.1,-0.4,-0.1,0.1,0,0.1}, -- handle
		{-0.3,0,-0.3,0.3,0.5,0.3}, -- upper part
	}
}

function tutorial.goldinfo(pos)
	local meta = minetest.get_meta(pos)
	meta:set_string("infotext", S("This golden cup has been awarded for finishing the tutorial."))
end

function tutorial.diamondinfo(pos)
	local meta = minetest.get_meta(pos)
	meta:set_string("infotext", S("This diamond cup has been awarded for collecting all hidden diamonds."))
end


--[[ awarded for collecting all gold ingots ]]
minetest.register_node("tutorial:cup_gold", {
	description = S("golden cup"),
	tiles = { "default_gold_block.png" },
	paramtype = "light",
	drawtype = "nodebox",
	node_box = tutorial.cupnodebox,
	selection_box = tutorial.cupselbox,
	groups = { creative_breakable = 1 },
	on_construct = tutorial.goldinfo,
})

--[[ awarded for collecting all diamonds ]]
minetest.register_node("tutorial:cup_diamond", {
	description = S("diamond cup"),
	tiles = { "default_diamond_block.png" },
	paramtype = "light",
	drawtype = "nodebox",
	node_box = tutorial.cupnodebox,
	selection_box = tutorial.cupselbox,
	groups = { creative_breakable = 1 },
	on_construct = tutorial.diamondinfo,
})

minetest.register_abm({
	nodenames = {"tutorial:cup_gold"},
	interval = 5,
	chance = 1,
	action = tutorial.goldinfo,
})

minetest.register_abm({
	nodenames = {"tutorial:cup_diamond"},
	interval = 5,
	chance = 1,
	action = tutorial.diamondinfo,
})

--[[ This function shows a simple dialog window with scrollable text
	name: name of the player to show the formspec to
	caption: Caption of the dialog window (not escaped)
	text: The text to be shown. Must be escaped manually for formspec, an unescaped
	      comma generates a line break.
]]
function tutorial.show_default_dialog(name, caption, text)
	local formspec = "size[12,6]"..
	text_box(caption, text)..
	"button_exit[4.5,5.5;3,1;close;"..S("Close").."]"
	minetest.show_formspec(name, "tutorial_dialog", formspec)
end

minetest.register_on_joinplayer(function(player)
	local formspec = nil
	local playerinfo = minetest.get_player_information(player:get_player_name())
	if(minetest.is_singleplayer() == false) then
		formspec = "size[12,6]"..
		text_box(NS("Warning: You're not playing in singleplayer mode"), tutorial.texts.notsingleplayer)..
		"button_exit[2.5,5.5;3,1;close;"..minetest.formspec_escape(S("Continue anyways")).."]"..
		"button_exit[6.5,5.5;3,1;leave;"..minetest.formspec_escape(S("Leave tutorial")).."]"
	elseif(not map_editing and minetest.settings:get_bool("creative_mode")) then
		formspec = "size[12,6]"..
		text_box(NS("Warning: Creative mode is active"), tutorial.texts.creative)..
		"button_exit[2.5,5.5;3,1;close;"..minetest.formspec_escape(S("Continue anyways")).."]"..
		"button_exit[6.5,5.5;3,1;leave;"..minetest.formspec_escape(S("Leave tutorial")).."]"
	elseif(not map_editing and playerinfo.touch_controls == true) then
		formspec = "size[12,6]"..
		text_box(NS("Keyboard and mouse recommended"), tutorial.texts.mobile)..
		"button_exit[2.5,5.5;3,1;showintro;"..minetest.formspec_escape(S("Continue anyways")).."]"..
		"button_exit[6.5,5.5;3,1;leave;"..minetest.formspec_escape(S("Leave tutorial")).."]"

	elseif(not map_editing and tutorial.state.intro_text == false) then
		formspec = "size[12,6]"..
		text_box(NS("Introduction"), tutorial.texts.intro)..
		"button_exit[4.5,5.5;3,1;close;"..minetest.formspec_escape(S("Close")).."]"
		tutorial.state.intro_text = true
	end
	if tutorial.state.first_join==true and tutorial.first_spawn then
		player:set_pos(tutorial.first_spawn.pos)
		player:set_look_horizontal(tutorial.first_spawn.yaw)
		tutorial.state.first_join = false
	end
	tutorial.save_state()
	if(formspec~=nil) then
		minetest.show_formspec(player:get_player_name(), "intro", formspec)
	end
end
)

local teleport_dialog = function(player)
	local formspec = "size[10,10]" ..
	"label[0,0;"..minetest.formspec_escape(S("Select teleport destination:")).."]"
	local y = 1
	local x = 0
	local id, data
	for i = 1, #tutorial.locations_order do
		local id = tutorial.locations_order[i]
		local data = tutorial.locations[id]
		local caption
		if id == "goodbye" then
			caption = S("Good-Bye room")
		else
			caption = S(tutorial.captions[id])
		end
		formspec = formspec .. "button_exit["..x..","..y..";5,1;".."teleport_"..id..";"..minetest.formspec_escape(caption).."]"
		y = y + 1
		if y > 9 then
			y = 1
			x = x + 5
		end
	end
	minetest.show_formspec(player:get_player_name(), "tutorial_teleport", formspec)
end

minetest.register_on_player_receive_fields(function(player, formname, fields)
	if(fields.leave) then
		local name = player:get_player_name()
		local reason = S("You have voluntarily exited the tutorial.")
		if minetest.disconnect_player then
			minetest.disconnect_player(name, reason)
		else
			minetest.kick_player(name, reason)
		end
		return
	elseif(fields.teleport) then
		teleport_dialog(player)
		return
	elseif(fields.gotoend) then
		tutorial.go_to_end(player)
		return
	elseif(fields.showintro) then
		if not tutorial.state.intro_text then
			local formspec = "size[12,6]"..
			text_box(NS("Introduction"), tutorial.texts.intro)..
			"button_exit[4.5,5.5;3,1;close;"..minetest.formspec_escape(S("Close")).."]"
			tutorial.state.intro_text = true
			tutorial.save_state()
			minetest.show_formspec(player:get_player_name(), "intro", formspec)
		end
	end
	if formname == "tutorial_teleport" then
		for id, data in pairs(tutorial.locations) do
			if(fields["teleport_"..id]) then
				tutorial.teleport(player, data[1], data[2], data[3])
				break
			end
		end
	end
end)

tutorial.steptimer = 0
minetest.register_globalstep(function(dtime)
	tutorial.steptimer = tutorial.steptimer + dtime
	local players = minetest.get_connected_players()
	if(tutorial.steptimer > 2) then
		for p=1,#players do
			local player = players[p]
			local name = player:get_player_name()
			do
				local inv = player:get_inventory()
				local state_changed = false

				if(tutorial.state.first_gold ~= true) then
					local gold_stack = ItemStack("tutorial_default:gold_ingot 1")
					if(inv:contains_item("main", gold_stack)) then
						tutorial.show_default_dialog(
							name,
							NS("Gold ingots in the tutorial"),
							tutorial.texts.first_gold
						)
						tutorial.state.first_gold = true
						state_changed = true
					end
				end
				if(tutorial.state.last_gold ~= true) then
					local gold_stack = ItemStack("tutorial_default:gold_ingot "..tostring(tutorial.gold))
					if(inv:contains_item("main", gold_stack)) then
						local formspec = "size[12,6]"..
						text_box(NS("You've finished the tutorial!"), tutorial.texts.last_gold)..
						"button_exit[0.5,5.5;3,1;close;"..minetest.formspec_escape(S("Continue")).."]"..
						"button_exit[4.5,5.5;3,1;leave;"..minetest.formspec_escape(S("Leave tutorial")).."]"..
						"button_exit[8.5,5.5;3,1;gotoend;"..minetest.formspec_escape(S("Go to Good-Bye room")).."]"

						minetest.show_formspec(name, "tutorial_last_gold", formspec)

						minetest.set_node({x=19,y=2,z=72}, {name="tutorial:cup_gold"})
						tutorial.state.last_gold = true
						state_changed = true
					end
				end

				if(tutorial.state.first_diamond ~= true) then
					local diamond_stack = ItemStack("tutorial_default:diamond 1")
					if(inv:contains_item("main", diamond_stack)) then
						tutorial.show_default_dialog(
							name,
							NS("You found a hidden diamond!"),
							tutorial.texts.first_diamond
						)
						tutorial.state.first_diamond = true
						state_changed = true
					end
				end
				if(tutorial.state.last_diamond ~= true) then
					local diamond_stack = ItemStack("tutorial_default:diamond "..tostring(tutorial.diamonds))
					if(inv:contains_item("main", diamond_stack)) then
						local formspec = "size[12,6]"..
						text_box(NS("You have collected all hidden diamonds!"), tutorial.texts.last_diamond)..
						"button_exit[2.5,5.5;3,1;close;"..minetest.formspec_escape(S("Continue")).."]"..
						"button_exit[6.5,5.5;3,1;gotoend;"..minetest.formspec_escape(S("Go to Good-Bye room")).."]"
						minetest.show_formspec(name, "tutorial_last_diamond", formspec)

						minetest.set_node({x=19,y=2,z=74}, {name="tutorial:cup_diamond"})
						tutorial.state.last_diamond = true
						state_changed = true
					end
				end

				if(state_changed) then
					tutorial.save_state()
				end
			end
		end
		tutorial.steptimer = 0
	end
end)

function tutorial.teleport(player, pos, look_horizontal, look_vertical)
	player:set_pos(pos)
	player:set_look_horizontal(look_horizontal)
	if not look_vertical then
		look_vertical = 0
	end
	player:set_look_vertical(look_vertical)
end

function tutorial.back_to_start(player)
	tutorial.teleport(player, tutorial.locations.intro[1], tutorial.locations.intro[2])
end

function tutorial.go_to_end(player)
	tutorial.teleport(player, tutorial.locations.goodbye[1], tutorial.locations.goodbye[2])
end

--[[
Helper tool for sign text extracting
must be called with /lua from luacmd
An ugly, quick and dirty hack.
]]

function tutorial.extract_texts()
	local filepath = minetest.get_modpath("tutorial").."/locale/template_texts.txt"
	local file = io.open(filepath, "w+")
	if(file) then
		for k,v in pairs(tutorial.texts) do
			file:write("# Tutorial text: "..k.."\n")
			file:write(v.."\n\n")
		end
	else
		minetest.log("error", "[tutorial] An attempt to write into "..filepath.." failed.")
	end
	io.close(file)
end

