1601 lines
60 KiB
Lua
1601 lines
60 KiB
Lua
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 ==
|
||
|
||
-- intllib support
|
||
local S
|
||
if (minetest.get_modpath("intllib")) then
|
||
S = intllib.Getter()
|
||
else
|
||
S = function ( s ) return s end
|
||
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
|
||
|
||
function tutorial.convert_newlines(str)
|
||
if(type(str)~="string") then
|
||
return "ERROR: No string found!"
|
||
end
|
||
|
||
local function convert(s)
|
||
return s:gsub("\n", function(slash, what)
|
||
return ","
|
||
end)
|
||
end
|
||
|
||
return convert(str)
|
||
end
|
||
|
||
function tutorial.register_infosign(itemstringpart, caption, fulltext)
|
||
tutorial.captions[itemstringpart] = caption
|
||
minetest.register_node("tutorial:sign_"..itemstringpart, {
|
||
description = string.format(S("tutorial sign '%s'"), 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)).."]"..
|
||
"tablecolumns[text]"..
|
||
"tableoptions[background=#000000;highlight=#000000;border=false]"..
|
||
"table[0,0.25;12,5.2;infosign_text;"..
|
||
tutorial.convert_newlines(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", string.format(S("%s (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]"..
|
||
"label[-0.15,-0.4;"..minetest.formspec_escape(S(caption)).."]"..
|
||
"tablecolumns[text]"..
|
||
"tableoptions[background=#000000;highlight=#000000;border=false]"..
|
||
"table[0,0.25;12,5.2;infosign_text;"..
|
||
tutorial.convert_newlines(minetest.formspec_escape(S(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", string.format(S("%s (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.intro =
|
||
[[Welcome! This tutorial will teach you the most crucial basics of Minetest.
|
||
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 =
|
||
[[Minetest itself is not a game, it is a game engine.
|
||
To be able to actually play it, you need something called a "game".
|
||
|
||
Don't worry, Minetest comes pre-installed with a rather simple default game,
|
||
called "Minetest Game".
|
||
|
||
This tutorial teaches you the basics of Minetest (the engine), things which are true for
|
||
all games. This tutorial does not teach you how to play a particular game, not
|
||
even the default one.]]
|
||
|
||
tutorial.texts.subgame =
|
||
[[Now since you probably now the basics, you may want to actually play or build something.
|
||
Minetest comes bundled with a default game, which you may try out now.
|
||
Sadly, there is currently no tutorial for the default game.
|
||
You may want to read the "Getting Started" section of the Community Wiki,
|
||
which is more specific about the default game.
|
||
Said document can be found at:
|
||
|
||
<https://wiki.minetest.net/Getting_Started>
|
||
|
||
Alternatively, you may check out one of the games which are shared on the Minetest forums.]]
|
||
|
||
|
||
tutorial.texts.creative =
|
||
[[The creative mode is turned on. If you are here to learn how to play Minetest,
|
||
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 =
|
||
[[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 =
|
||
[=[Minetest 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 =
|
||
[=[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.
|
||
|
||
There are 2 minimap modes and 3 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. Currently,
|
||
radar mode does not work in the tutorial. Sorry, you have to try it
|
||
out in games.
|
||
|
||
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 =
|
||
[[The world of Minetest 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 =
|
||
[[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 =
|
||
[[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 =
|
||
[[These nasty blocks on the floor prevent you from jumping when you stand on them.]]
|
||
|
||
tutorial.texts.bouncy =
|
||
[[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 =
|
||
[[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 =
|
||
[[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 =
|
||
[=[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 =
|
||
[[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 =
|
||
[=[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 Minetest.
|
||
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 =
|
||
[[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 =
|
||
[[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 =
|
||
[[Treasure chests are a common sight in Minetest. They are actually not built-in
|
||
into the game.]]
|
||
|
||
tutorial.texts.damageblock =
|
||
[[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 Minetest.]]
|
||
|
||
tutorial.texts.ladder =
|
||
[[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 =
|
||
[[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 =
|
||
[=[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 = ""..
|
||
[=[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 =
|
||
[=[Liquids behave somewhat weirdly in Minetest. 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.
|
||
|
||
Minetest 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 =
|
||
[[Minetest 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 =
|
||
[[An important general concept in Minetest is pointing. As mentioned earlier,
|
||
there is a crosshair in the center of the screen.
|
||
|
||
You can point several things in Minetest:
|
||
|
||
- 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 =
|
||
[[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 =
|
||
[[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 Minetest.
|
||
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 =
|
||
[[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 =
|
||
[[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 =
|
||
[[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 Minetest 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 =
|
||
[[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 =
|
||
[=[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 =
|
||
[[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 =
|
||
[[Another important task in Minetest 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 =
|
||
[=[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 =
|
||
[[Mining is a method to remove a single block with a mining tool. It is a very important
|
||
task in Minetest 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 =
|
||
[[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 =
|
||
[[These are wooden planks. In the tutorial, you can only mine those blocks with an axe.
|
||
Wooden planks drop themselves.
|
||
|
||
In Minetest, we use the term "mining" in a general sense, regardless of the material.]]
|
||
|
||
tutorial.texts.mine_conglomerate =
|
||
[[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 =
|
||
[[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 =
|
||
[[This is stone. You need a pickaxe to mine it. When mined, stone will drop cobblestone.]]
|
||
|
||
tutorial.texts.mine_immortal =
|
||
[[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 =
|
||
[[Crafting is the task of taking several items and combining them to form a new item.
|
||
Crafting is another important task in Minetest.
|
||
|
||
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 =
|
||
[[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 =
|
||
[[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 =
|
||
[[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 =
|
||
[[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 =
|
||
[[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 =
|
||
[=[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 =
|
||
[[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 Minetest.
|
||
|
||
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 =
|
||
[[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 =
|
||
[[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 Minetest.]]
|
||
|
||
tutorial.texts.first_diamond =
|
||
[[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 =
|
||
[[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 =
|
||
[[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 =
|
||
[[You may want to check out these online resources related to Minetest:
|
||
|
||
Official homepage of Minetest: <https://minetest.net/>
|
||
The main place to find the most recent version of Minetest.
|
||
|
||
Community wiki: <https://wiki.minetest.net/>
|
||
A community-based documentation website for Minetest. Anyone with an account can edit
|
||
it! It also features a documentation of the default game, which was NOT covered by
|
||
this tutorial.
|
||
|
||
Webforums: <https://forum.minetest.net/>
|
||
A web-based discussion platform where you can discuss everything related to Minetest.
|
||
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 Minetest 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", "Introduction", tutorial.texts.intro)
|
||
tutorial.register_infosign("minetest", "Minetest", tutorial.texts.minetest)
|
||
tutorial.register_infosign("cam", "Player Camera", tutorial.texts.cam)
|
||
tutorial.register_infosign("minimap", "Minimap", tutorial.texts.minimap)
|
||
tutorial.register_infosign("runover", "Small Abysses", tutorial.texts.runover)
|
||
tutorial.register_infosign("jumpup", "Jumping (1)", tutorial.texts.jumpup)
|
||
tutorial.register_infosign("jumpover", "Jumping (2)", tutorial.texts.jumpover)
|
||
tutorial.register_infosign("sneak", "Sneaking", tutorial.texts.sneak)
|
||
tutorial.register_infosign("orientation", "Information about the following tutorial sections", tutorial.texts.orientation)
|
||
tutorial.register_infosign("hotbar", "Hotbar", tutorial.texts.hotbar)
|
||
tutorial.register_infosign("eat", "Comestibles and Eating", tutorial.texts.eat)
|
||
tutorial.register_infosign("chest", "Chests", tutorial.texts.chest)
|
||
tutorial.register_infosign("damageblock", "Blocks Which Hurt You", tutorial.texts.damageblock)
|
||
tutorial.register_infosign("ladder", "Climbing Ladders", tutorial.texts.ladder)
|
||
tutorial.register_infosign("swim", "Swimming", tutorial.texts.swim)
|
||
tutorial.register_infosign("dive", "Diving", tutorial.texts.dive)
|
||
tutorial.register_infosign("waterfall", "Swimming up a Waterfall", tutorial.texts.waterfall)
|
||
tutorial.register_infosign("viscosity", "Viscosity", tutorial.texts.viscosity)
|
||
tutorial.register_infosign("liquidtypes", "Liquid sources and flowing liquids", tutorial.texts.liquidtypes)
|
||
tutorial.register_infosign("pointing1", "Pointing (1)", tutorial.texts.pointing1)
|
||
tutorial.register_infosign("pointing2", "Pointing (2)", tutorial.texts.pointing2)
|
||
tutorial.register_infosign("health", "Health and Damage", tutorial.texts.health)
|
||
tutorial.register_infosign("death", "Death and Respawning", tutorial.texts.death)
|
||
tutorial.register_infosign("items", "Items", tutorial.texts.items)
|
||
tutorial.register_infosign("tools", "Tools", tutorial.texts.tools)
|
||
tutorial.register_infosign("inventory", "Using the Inventory", tutorial.texts.inventory)
|
||
tutorial.register_infosign("listrings", "Inventory shortcut", tutorial.texts.listrings)
|
||
tutorial.register_infosign("chest", "Comment About Chests", tutorial.texts.chest)
|
||
tutorial.register_infosign("build", "Building Some Blocks", tutorial.texts.build)
|
||
tutorial.register_infosign("build_special", "Building at Usable Blocks", tutorial.texts.build_special)
|
||
tutorial.register_infosign("mine", "Mining blocks", tutorial.texts.mine)
|
||
tutorial.register_infosign("mine_cobble", "Mining example: Cobblestone", tutorial.texts.mine_cobble)
|
||
tutorial.register_infosign("mine_stone", "Mining example: Stone", tutorial.texts.mine_stone)
|
||
tutorial.register_infosign("mine_conglomerate", "Mining example: Conglomerate", tutorial.texts.mine_conglomerate)
|
||
tutorial.register_infosign("mine_wood", "Mining example: Wooden Planks", tutorial.texts.mine_wood)
|
||
tutorial.register_infosign("mine_glass", "Mining example: Weak glass", tutorial.texts.mine_glass)
|
||
tutorial.register_infosign("mine_immortal", "Unminable blocks", tutorial.texts.mine_immortal)
|
||
tutorial.register_infosign("blocks", "Special blocks", tutorial.texts.blocks)
|
||
tutorial.register_infosign("disable_jump", "No-jumping blocks", tutorial.texts.disable_jump)
|
||
tutorial.register_infosign("bouncy", "Bouncy blocks", tutorial.texts.bouncy)
|
||
tutorial.register_infosign("falling_node", "Falling blocks", tutorial.texts.falling_node)
|
||
tutorial.register_infosign("attached_node", "Attached blocks", tutorial.texts.attached_node)
|
||
tutorial.register_infosign("use", "Using blocks", tutorial.texts.use)
|
||
tutorial.register_infosign("craft1", "Crafting Basics", tutorial.texts.craft1)
|
||
tutorial.register_infosign("craft2", "Crafting using Shapeless Recipes", tutorial.texts.craft2)
|
||
tutorial.register_infosign("craft3", "Crafting Faster", tutorial.texts.craft3)
|
||
tutorial.register_infosign("craft4", "Crafting Groups", tutorial.texts.craft4)
|
||
tutorial.register_infosign("smelt", "Furnace Operation Instructions", tutorial.texts.smelt)
|
||
tutorial.register_infosign("repair", "Repairing Tools", tutorial.texts.repair)
|
||
tutorial.register_infosign("basic_end", "End of the Basic Tutorial", tutorial.texts.basic_end)
|
||
tutorial.register_infosign("controls", "Controls Overview", tutorial.texts.controls)
|
||
tutorial.register_infosign("online", "Online Resources", tutorial.texts.online)
|
||
tutorial.register_infosign("subgame", "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]"..
|
||
"label[-0.15,-0.4;"..minetest.formspec_escape(caption).."]"..
|
||
"tablecolumns[text]"..
|
||
"tableoptions[background=#000000;highlight=#000000;border=false]"..
|
||
"table[0,0.25;12,5.2;text_table;"..
|
||
tutorial.convert_newlines(minetest.formspec_escape(S(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
|
||
if(minetest.is_singleplayer() == false) then
|
||
formspec = "size[12,6]"..
|
||
"label[-0.15,-0.4;"..minetest.formspec_escape(S("Warning: You're not playing in singleplayer mode")).."]"..
|
||
"tablecolumns[text]"..
|
||
"tableoptions[background=#000000;highlight=#000000;border=false]"..
|
||
"table[0,0.25;12,5.2;creative_text;"..
|
||
tutorial.convert_newlines(minetest.formspec_escape(S(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]"..
|
||
"label[-0.15,-0.4;"..(minetest.formspec_escape(S("Warning: Creative mode is active"))).."]"..
|
||
"tablecolumns[text]"..
|
||
"tableoptions[background=#000000;highlight=#000000;border=false]"..
|
||
"table[0,0.25;12,5.2;creative_text;"..
|
||
tutorial.convert_newlines(minetest.formspec_escape(S(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 tutorial.state.intro_text == false) then
|
||
formspec = "size[12,6]"..
|
||
"label[-0.15,-0.4;"..minetest.formspec_escape(S("Introduction")).."]"..
|
||
"tablecolumns[text]"..
|
||
"tableoptions[background=#000000;highlight=#000000;border=false]"..
|
||
"table[0,0.25;12,5.2;intro_text;"..
|
||
tutorial.convert_newlines(minetest.formspec_escape(S(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
|
||
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,
|
||
S("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]"..
|
||
"label[-0.15,-0.4;"..minetest.formspec_escape(S("You've finished the tutorial!")).."]"..
|
||
"tablecolumns[text]"..
|
||
"tableoptions[background=#000000;highlight=#000000;border=false]"..
|
||
"table[0,0.25;12,5.2;creative_text;"..
|
||
tutorial.convert_newlines(minetest.formspec_escape(S(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,
|
||
S("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]"..
|
||
"label[-0.15,-0.4;"..minetest.formspec_escape(S("You have collected all hidden diamonds!")).."]"..
|
||
"tablecolumns[text]"..
|
||
"tableoptions[background=#000000;highlight=#000000;border=false]"..
|
||
"table[0,0.25;12,5.2;last_diamond_text;"..
|
||
tutorial.convert_newlines(minetest.formspec_escape(S(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 tools for sign text extracting
|
||
must be called with /lua from luacmd
|
||
An ugly, quick and dirty hack.
|
||
TODO: Toss away intllib in favor of gettext as soon as possible
|
||
]]
|
||
|
||
function tutorial.convert_newlines_for_intllib(str)
|
||
local function convert(s)
|
||
return s:gsub("\n", function(slash, what)
|
||
return "\\n"
|
||
end)
|
||
end
|
||
|
||
return convert(str)
|
||
end
|
||
|
||
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(tutorial.convert_newlines_for_intllib(v).."\n\n")
|
||
end
|
||
else
|
||
minetest.log("error", "[tutorial] An attempt to write into "..filepath.." failed.")
|
||
end
|
||
io.close(file)
|
||
end
|
||
|