Compare commits

...

5 Commits

Author SHA1 Message Date
Wuzzy 767eb58b95 Version 3.3.0 2022-08-03 09:43:34 +02:00
Wuzzy 3bcaab4da2 Update mod names in README 2022-08-02 15:54:48 +02:00
Wuzzy 27edb029ca Fix spawning of infinite rocks 2022-08-02 15:51:27 +02:00
Wuzzy cb1cee225c Rename mod: mpd → tutorial_music 2022-08-02 15:36:13 +02:00
Wuzzy 288ec1a5da Rename mod: supplemental → tutorial_supplemental 2022-08-02 15:28:27 +02:00
42 changed files with 158 additions and 130 deletions

View File

@ -2,7 +2,7 @@
Created by Wuzzy Created by Wuzzy
Version: 3.2.0 Version: 3.3.0
Playable in Minetest 5.5.0 or later. Playable in Minetest 5.5.0 or later.
Learn how to use and play Minetest in a nice and cozy castle. Here you learn most of the basics of Minetest and how to play. Learn how to use and play Minetest in a nice and cozy castle. Here you learn most of the basics of Minetest and how to play.
@ -23,7 +23,7 @@ Depending on your operating system, you have to put it into the following direct
* GNU/Linux: $HOME/.minetest/games, where “$HOME” refers to your home directory. * GNU/Linux: $HOME/.minetest/games, where “$HOME” refers to your home directory.
* MacOS: $HOME/.minetest/games, where “$HOME” refers to your home directory. * MacOS: $HOME/.minetest/games, where “$HOME” refers to your home directory.
* Windows: into the "games" sub-directory of the program folder in which you have installed Minetest. It is the directory containing the directories (not necessarily exhaustive list) bin (which in turn contains minetest.exe), builtin, client, doc, fonts, games, locale, mods and textures. * Windows: into the "games" sub-directory of the program folder in which you have installed Minetest. It is the directory containing the directories (not necessarily exhaustive list) bin (which in turn contains minetest.exe), builtin, client, doc, fonts, games, locale, mods and textures.
## How to use ## How to use
@ -61,7 +61,7 @@ There's also a secret prize, can you win it?
## Legalities ## Legalities
This tutorial is free software. You can legally study, copy, share, transform, remix, distribute this to your liking, under certain conditions. This tutorial is free software. You can legally study, copy, share, transform, remix, distribute this to your liking, under certain conditions.
The mods “`tutorial`” and “supplemental” as well the tutorial world are original work by Wuzzy and fall under the MIT License. The mods “`tutorial`” and “`tutorial_supplemental`” as well the tutorial world are original work by Wuzzy and fall under the MIT License.
The mod “`tutorial_mapgen`” (Tutorial World generator) is also original work by Wuzzy, same license, but it contains contributions. The mod “`tutorial_mapgen`” (Tutorial World generator) is also original work by Wuzzy, same license, but it contains contributions.
Contributions: Contributions:
@ -71,15 +71,15 @@ Contributions:
Other mods are creation by other people, but heavily modified to fit the Tutorial's needs. Other mods are creation by other people, but heavily modified to fit the Tutorial's needs.
The mods “`default`” and “`creative`” falls under the GNU LGPLv2.1 for the code and the CC BY-SA 3.0 for artwork. The mods “`tutorial_default`” and “`tutorial_creative`” falls under the GNU LGPLv2.1 for the code and the CC BY-SA 3.0 for artwork.
The mod “`darkage`” falls under the MIT License. The mod “`tutorial_darkage`” falls under the MIT License.
The mod “`mpd`” falls under the MIT License for the code and the CC BY 3.0 for the music. The mod “`tutorial_music`” falls under the MIT License for the code and the CC BY 3.0 for the music.
The mod “`castle`” falls under the MIT License (the author allowed me an exception). The mod “`tutorial_castle`” falls under the MIT License (the author allowed me an exception).
The mod “`arrow_signs`” falls under the CC BY-SA 3.0. The mod “`tutorial_arrow_signs`” falls under the CC BY-SA 3.0.
The mod “`areas`” falls under the GNU LGPLv2.1 (or later). The mod “`tutorial_areas`” falls under the GNU LGPLv2.1 (or later).
The mod “`cottages`” falls under the GNU GPLv2 (the author allowed me an exception). The mod “`tutorial_cottages`” falls under the GNU GPLv2 (the author allowed me an exception).
The mod “`show_wielded_item`” is licensed under the GNU LGPLv2 or later. The mod “`show_wielded_item`” is licensed under the GNU LGPLv2 or later.
The mod “`supplemental`” falls under the MIT License, with one exception: The mod “`tutorial_supplemental`” falls under the MIT License, with one exception:
The texture `supplemental_loudspeaker.png` falls under the CC BY-SA 3.0 (from the developers of the Mesecons mod). The texture `supplemental_loudspeaker.png` falls under the CC BY-SA 3.0 (from the developers of the Mesecons mod).
Everything else falls under the MIT License. Everything else falls under the MIT License.

View File

@ -1 +0,0 @@
name = mpd

View File

@ -1,3 +0,0 @@
name = supplemental
depends = tutorial_default, mpd
optional_depends = intllib

View File

@ -1181,9 +1181,13 @@ minetest.register_node("tutorial:itemspawner", {
local offset = minetest.string_to_pos(meta:get_string("offset")) local offset = minetest.string_to_pos(meta:get_string("offset"))
local itemstring = meta:get_string("itemstring") local itemstring = meta:get_string("itemstring")
local alias = minetest.registered_aliases[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 if alias then
itemstring = alias test_item:set_name(alias)
itemstring = test_item:to_string()
end end
local x, y, z = offset.x, offset.y, offset.z 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 spawnpos = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
@ -1191,7 +1195,9 @@ minetest.register_node("tutorial:itemspawner", {
for o=1, #objs do for o=1, #objs do
local ent = objs[o]:get_luaentity() local ent = objs[o]:get_luaentity()
if ent then if ent then
if ent.name == "__builtin:item" and ent.itemstring == itemstring 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. -- Remove node when item was spawned successfully.
-- So it doesn't get in the way. -- So it doesn't get in the way.
minetest.remove_node(pos) minetest.remove_node(pos)

View File

@ -28,7 +28,7 @@ function default.get_hotbar_bg(x,y)
end end
local music = "" local music = ""
if minetest.get_modpath("mpd") then if minetest.get_modpath("tutorial_music") then
music = "button[-0.1,0.7;3,1;togglemusic;"..minetest.formspec_escape(S("Toggle music")).."]" music = "button[-0.1,0.7;3,1;togglemusic;"..minetest.formspec_escape(S("Toggle music")).."]"
end end

View File

@ -1,2 +1,2 @@
name = tutorial_default name = tutorial_default
optional_depends = intllib optional_depends = intllib, tutorial_music

View File

@ -1,46 +1,46 @@
mpd={} tutorial_music={}
--config --config
mpd.pause_between_songs=7 tutorial_music.pause_between_songs=7
--end config --end config
mpd.modpath=minetest.get_modpath("mpd") tutorial_music.modpath=minetest.get_modpath("tutorial_music")
if not mpd.modpath then if not tutorial_music.modpath then
error("mpd mod folder has to be named 'mpd'!") error("mod folder has to be named 'tutorial_music'!")
end end
--{name, length, gain~1} --{name, length, gain~1}
mpd.songs = {} tutorial_music.songs = {}
local sfile, sfileerr=io.open(mpd.modpath.."/songs.txt") local sfile, sfileerr=io.open(tutorial_music.modpath.."/songs.txt")
if not sfile then error("Error opening songs.txt: "..sfileerr) end if not sfile then error("Error opening songs.txt: "..sfileerr) end
for line in sfile:lines() do for line in sfile:lines() do
if line~="" and line[1]~="#" then if line~="" and line[1]~="#" then
local name, timeMinsStr, timeSecsStr, gainStr = string.match(line, "^(%S+)%s+(%d+):([%d%.]+)%s+([%d%.]+)$") local name, timeMinsStr, timeSecsStr, gainStr = string.match(line, "^(%S+)%s+(%d+):([%d%.]+)%s+([%d%.]+)$")
local timeMins, timeSecs, gain = tonumber(timeMinsStr), tonumber(timeSecsStr), tonumber(gainStr) local timeMins, timeSecs, gain = tonumber(timeMinsStr), tonumber(timeSecsStr), tonumber(gainStr)
if name and timeMins and timeSecs and gain then if name and timeMins and timeSecs and gain then
mpd.songs[#mpd.songs+1]={name=name, length=timeMins*60+timeSecs, lengthhr=timeMinsStr..":"..timeSecsStr, gain=gain} tutorial_music.songs[#tutorial_music.songs+1]={name=name, length=timeMins*60+timeSecs, lengthhr=timeMinsStr..":"..timeSecsStr, gain=gain}
else else
minetest.log("warning", "[mpd] Misformatted song entry in songs.txt: "..line) minetest.log("warning", "[tutorial_music] Misformatted song entry in songs.txt: "..line)
end end
end end
end end
sfile:close() sfile:close()
if #mpd.songs==0 then if #tutorial_music.songs==0 then
print("[mpd]no songs registered, not doing anything") minetest.log("error", "[tutorial_music] no songs registered, not doing anything")
return return
end end
mpd.storage = minetest.get_mod_storage() tutorial_music.storage = minetest.get_mod_storage()
mpd.handles={} tutorial_music.handles={}
mpd.playing=false tutorial_music.playing=false
mpd.id_playing=nil tutorial_music.id_playing=nil
mpd.song_time_left=nil tutorial_music.song_time_left=nil
mpd.time_next=10 --sekunden tutorial_music.time_next=10 --sekunden
mpd.id_last_played=nil tutorial_music.id_last_played=nil
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
local meta = player:get_meta() local meta = player:get_meta()
@ -52,131 +52,131 @@ minetest.register_on_joinplayer(function(player)
play = false play = false
end end
if play then if play then
mpd.next_song() tutorial_music.next_song()
else else
mpd.stop_song() tutorial_music.stop_song()
end end
end) end)
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
if mpd.playing then if tutorial_music.playing then
if mpd.song_time_left<=0 then if tutorial_music.song_time_left<=0 then
mpd.stop_song() tutorial_music.stop_song()
mpd.time_next=mpd.pause_between_songs tutorial_music.time_next=tutorial_music.pause_between_songs
else else
mpd.song_time_left=mpd.song_time_left-dtime tutorial_music.song_time_left=tutorial_music.song_time_left-dtime
end end
elseif mpd.time_next then elseif tutorial_music.time_next then
if mpd.time_next<=0 then if tutorial_music.time_next<=0 then
mpd.next_song() tutorial_music.next_song()
else else
mpd.time_next=mpd.time_next-dtime tutorial_music.time_next=tutorial_music.time_next-dtime
end end
end end
end) end)
mpd.play_song=function(id) tutorial_music.play_song=function(id)
if mpd.playing then if tutorial_music.playing then
mpd.stop_song() tutorial_music.stop_song()
end end
local song=mpd.songs[id] local song=tutorial_music.songs[id]
if not song then return end if not song then return end
for _,player in ipairs(minetest.get_connected_players()) do for _,player in ipairs(minetest.get_connected_players()) do
local pname=player:get_player_name() local pname=player:get_player_name()
local pvolume=tonumber(mpd.storage:get_string("vol_"..pname)) local pvolume=tonumber(tutorial_music.storage:get_string("vol_"..pname))
if not pvolume then pvolume=1 end if not pvolume then pvolume=1 end
if pvolume>0 then if pvolume>0 then
local handle = minetest.sound_play(song.name, {to_player=pname, gain=song.gain*pvolume}) local handle = minetest.sound_play(song.name, {to_player=pname, gain=song.gain*pvolume})
if handle then if handle then
mpd.handles[pname]=handle tutorial_music.handles[pname]=handle
end end
end end
end end
mpd.playing=id tutorial_music.playing=id
--adding 2 seconds as security --adding 2 seconds as security
mpd.song_time_left = song.length + 2 tutorial_music.song_time_left = song.length + 2
end end
mpd.stop_song=function() tutorial_music.stop_song=function()
for pname, handle in pairs(mpd.handles) do for pname, handle in pairs(tutorial_music.handles) do
minetest.sound_stop(handle) minetest.sound_stop(handle)
end end
mpd.id_last_played=mpd.playing tutorial_music.id_last_played=tutorial_music.playing
mpd.playing=nil tutorial_music.playing=nil
mpd.handles={} tutorial_music.handles={}
mpd.time_next=nil tutorial_music.time_next=nil
end end
mpd.next_song=function() tutorial_music.next_song=function()
local next local next
repeat repeat
next=math.random(1,#mpd.songs) next=math.random(1,#tutorial_music.songs)
until #mpd.songs==1 or next~=mpd.id_last_played until #tutorial_music.songs==1 or next~=tutorial_music.id_last_played
mpd.play_song(next) tutorial_music.play_song(next)
end end
mpd.song_human_readable=function(id) tutorial_music.song_human_readable=function(id)
local song=mpd.songs[id] local song=tutorial_music.songs[id]
return id..": "..song.name.." ["..song.lengthhr.."]" return id..": "..song.name.." ["..song.lengthhr.."]"
end end
minetest.register_privilege("mpd", "may control the music player daemon (mpd) mod") minetest.register_privilege("mpd", "May control the music")
minetest.register_chatcommand("mpd_stop", { minetest.register_chatcommand("music_stop", {
params = "", params = "",
description = "Stop the song currently playing", description = "Stop the song currently playing",
privs = {mpd=true}, privs = {mpd=true},
func = function(name, param) func = function(name, param)
local player = minetest.get_player_by_name(name) local player = minetest.get_player_by_name(name)
player:get_meta():set_string("play_music", "0") player:get_meta():set_string("play_music", "0")
mpd.stop_song() tutorial_music.stop_song()
end, end,
}) })
minetest.register_chatcommand("mpd_list", { minetest.register_chatcommand("music_list", {
params = "", params = "",
description = "List all available songs and their IDs", description = "List all available songs and their IDs",
privs = {mpd=true}, privs = {mpd=true},
func = function(name, param) func = function(name, param)
for k,v in ipairs(mpd.songs) do for k,v in ipairs(tutorial_music.songs) do
minetest.chat_send_player(name, mpd.song_human_readable(k)) minetest.chat_send_player(name, tutorial_music.song_human_readable(k))
end end
end, end,
}) })
minetest.register_chatcommand("mpd_play", { minetest.register_chatcommand("music_play", {
params = "<id>", params = "<id>",
description = "Play the songs with the given ID (see ids with /mpd_list)", description = "Play the songs with the given ID (see IDs with /music_list)",
privs = {mpd=true}, privs = {mpd=true},
func = function(name, param) func = function(name, param)
id=tonumber(param) id=tonumber(param)
if id and id>0 and id<=#mpd.songs then if id and id>0 and id<=#tutorial_music.songs then
local player = minetest.get_player_by_name(name) local player = minetest.get_player_by_name(name)
player:get_meta():set_string("play_music", "1") player:get_meta():set_string("play_music", "1")
mpd.play_song(id) tutorial_music.play_song(id)
return true,"Playing: "..mpd.song_human_readable(id) return true,"Playing: "..tutorial_music.song_human_readable(id)
end end
return false, "Invalid song ID!" return false, "Invalid song ID!"
end, end,
}) })
minetest.register_chatcommand("mpd_what", { minetest.register_chatcommand("music_what", {
params = "", params = "",
description = "Display the currently played song.", description = "Display the currently played song.",
privs = {mpd=true}, privs = {mpd=true},
func = function(name, param) func = function(name, param)
if not mpd.playing then return true,"Nothing playing, "..math.floor(mpd.time_next or 0).." sec. left until next song." end if not tutorial_music.playing then return true,"Nothing playing, "..math.floor(tutorial_music.time_next or 0).." sec. left until next song." end
return true,"Playing: "..mpd.song_human_readable(mpd.playing).."\nTime Left: "..math.floor(mpd.song_time_left or 0).." sec." return true,"Playing: "..tutorial_music.song_human_readable(tutorial_music.playing).."\nTime left: "..math.floor(tutorial_music.song_time_left or 0).." sec."
end, end,
}) })
minetest.register_chatcommand("mpd_next", { minetest.register_chatcommand("music_next", {
params = "[seconds]", params = "[seconds]",
description = "Start the next song, either immediately (no parameters) or after n seconds.", description = "Start the next song, either immediately (no parameters) or after n seconds.",
privs = {mpd=true}, privs = {mpd=true},
func = function(name, param) func = function(name, param)
local player = minetest.get_player_by_name(name) local player = minetest.get_player_by_name(name)
player:get_meta():set_string("play_music", "1") player:get_meta():set_string("play_music", "1")
mpd.stop_song() tutorial_music.stop_song()
if param and tonumber(param) then if param and tonumber(param) then
mpd.time_next=tonumber(param) tutorial_music.time_next=tonumber(param)
return true,"Next song in "..param.." seconds!" return true,"Next song in "..param.." seconds!"
else else
mpd.next_song() tutorial_music.next_song()
return true,"Next song started!" return true,"Next song started!"
end end
end, end,
@ -187,13 +187,13 @@ minetest.register_chatcommand("mvolume", {
privs = {}, privs = {},
func = function(pname, param) func = function(pname, param)
if not param or param=="" then if not param or param=="" then
local pvolume=tonumber(mpd.storage:get_string("vol_"..pname)) local pvolume=tonumber(tutorial_music.storage:get_string("vol_"..pname))
if not pvolume then pvolume=1 end if not pvolume then pvolume=1 end
if pvolume>0 then if pvolume>0 then
return true, "Your music volume is set to "..pvolume.."." return true, "Your music volume is set to "..pvolume.."."
else else
if mpd.handles[pname] then if tutorial_music.handles[pname] then
minetest.sound_stop(mpd.handles[pname]) minetest.sound_stop(tutorial_music.handles[pname])
end end
return true, "Background music is disabled for you. Use '/mvolume 1' to enable it again." return true, "Background music is disabled for you. Use '/mvolume 1' to enable it again."
end end
@ -204,12 +204,12 @@ minetest.register_chatcommand("mvolume", {
end end
pvolume = math.min(pvolume, 1) pvolume = math.min(pvolume, 1)
pvolume = math.max(pvolume, 0) pvolume = math.max(pvolume, 0)
mpd.storage:set_string("vol_"..pname, pvolume) tutorial_music.storage:set_string("vol_"..pname, pvolume)
if pvolume>0 then if pvolume>0 then
return true, "Music volume set to "..pvolume..". Change will take effect when the next song starts." return true, "Music volume set to "..pvolume..". Change will take effect when the next song starts."
else else
if mpd.handles[pname] then if tutorial_music.handles[pname] then
minetest.sound_stop(mpd.handles[pname]) minetest.sound_stop(tutorial_music.handles[pname])
end end
return true, "Disabled background music for you. Use /mvol to enable it again." return true, "Disabled background music for you. Use /mvol to enable it again."
end end
@ -218,11 +218,11 @@ minetest.register_chatcommand("mvolume", {
minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.register_on_player_receive_fields(function(player, formname, fields)
if(fields.togglemusic) then if(fields.togglemusic) then
if mpd.playing then if tutorial_music.playing then
mpd.stop_song() tutorial_music.stop_song()
player:get_meta():set_string("play_music", "0") player:get_meta():set_string("play_music", "0")
else else
mpd.next_song() tutorial_music.next_song()
player:get_meta():set_string("play_music", "1") player:get_meta():set_string("play_music", "1")
end end
end end

View File

@ -0,0 +1 @@
name = tutorial_music

View File

@ -1,7 +1,9 @@
### mpd Mod for Minetest ### Tutorial music mod
(c) 2017 orwell96
Slightly modified for the Tutorial. Based on the MPD mod ((c) 2017 orwell96)
Modified for the Tutorial.
This mod is licensed under the MIT License. This mod is licensed under the MIT License.

View File

@ -6,7 +6,7 @@ else
S = function ( s ) return s end S = function ( s ) return s end
end end
minetest.register_node("supplemental:sticky", { minetest.register_node("tutorial_supplemental:sticky", {
description = S("sticky stone brick"), description = S("sticky stone brick"),
tiles = {"default_stone_brick.png^supplemental_splat.png", tiles = {"default_stone_brick.png^supplemental_splat.png",
"default_stone_brick.png", "default_stone_brick.png", "default_stone_brick.png", "default_stone_brick.png", "default_stone_brick.png", "default_stone_brick.png",
@ -15,7 +15,7 @@ minetest.register_node("supplemental:sticky", {
sounds = default.node_sound_stone_defaults() sounds = default.node_sound_stone_defaults()
}) })
minetest.register_node("supplemental:bouncy", { minetest.register_node("tutorial_supplemental:bouncy", {
description = S("bouncy block"), description = S("bouncy block"),
tiles = {"supplemental_bouncy.png"}, tiles = {"supplemental_bouncy.png"},
groups = {creative_breakable=1, bouncy=70, fall_damage_add_percent=-100}, groups = {creative_breakable=1, bouncy=70, fall_damage_add_percent=-100},
@ -24,22 +24,22 @@ minetest.register_node("supplemental:bouncy", {
minetest.register_node("supplemental:conglomerate", { minetest.register_node("tutorial_supplemental:conglomerate", {
description = S("conglomerate"), description = S("conglomerate"),
tiles = {"supplemental_conglomerate.png" }, tiles = {"supplemental_conglomerate.png" },
groups = {cracky=3}, groups = {cracky=3},
drop = { items = { drop = { items = {
{ items={"supplemental:rock"} }, { items={"tutorial_supplemental:rock"} },
{ items={"supplemental:rock"}, rarity = 5 }, { items={"tutorial_supplemental:rock"}, rarity = 5 },
{ items={"supplemental:rock"}, rarity = 5 }, { items={"tutorial_supplemental:rock"}, rarity = 5 },
{ items={"supplemental:rock"}, rarity = 5 }, { items={"tutorial_supplemental:rock"}, rarity = 5 },
{ items={"supplemental:rock"}, rarity = 5 }, { items={"tutorial_supplemental:rock"}, rarity = 5 },
} }
}, },
sounds = default.node_sound_stone_defaults() sounds = default.node_sound_stone_defaults()
}) })
minetest.register_node("supplemental:frame",{ minetest.register_node("tutorial_supplemental:frame",{
description = S("picture frame"), description = S("picture frame"),
drawtype = "signlike", drawtype = "signlike",
selection_box = { type = "wallmounted" }, selection_box = { type = "wallmounted" },
@ -55,7 +55,7 @@ minetest.register_node("supplemental:frame",{
sounds = default.node_sound_defaults(), sounds = default.node_sound_defaults(),
}) })
minetest.register_node("supplemental:spikes", { minetest.register_node("tutorial_supplemental:spikes", {
description = S("short spikes"), description = S("short spikes"),
tiles = {"supplemental_spikes_small.png"}, tiles = {"supplemental_spikes_small.png"},
inventory_image = "supplemental_spikes_small.png", inventory_image = "supplemental_spikes_small.png",
@ -76,7 +76,7 @@ minetest.register_node("supplemental:spikes", {
} }
}) })
minetest.register_node("supplemental:spikes_large", { minetest.register_node("tutorial_supplemental:spikes_large", {
description = S("long spikes"), description = S("long spikes"),
tiles = {"supplemental_spikes_large.png"}, tiles = {"supplemental_spikes_large.png"},
inventory_image = "supplemental_spikes_large.png", inventory_image = "supplemental_spikes_large.png",
@ -96,18 +96,18 @@ local set_loudspeaker_infotext = function(pos)
meta:set_string("infotext", S("loudspeaker (rightclick to toggle music)")) meta:set_string("infotext", S("loudspeaker (rightclick to toggle music)"))
end end
minetest.register_node("supplemental:loudspeaker", { minetest.register_node("tutorial_supplemental:loudspeaker", {
description = S("loudspeaker"), description = S("loudspeaker"),
tiles = {"supplemental_loudspeaker.png"}, tiles = {"supplemental_loudspeaker.png"},
groups = { creative_breakable = 1 }, groups = { creative_breakable = 1 },
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
on_construct = set_loudspeaker_infotext, on_construct = set_loudspeaker_infotext,
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
if mpd.playing then if tutorial_music.playing then
mpd.stop_song() tutorial_music.stop_song()
clicker:get_meta():set_string("play_music", "0") clicker:get_meta():set_string("play_music", "0")
else else
mpd.next_song() tutorial_music.next_song()
clicker:get_meta():set_string("play_music", "1") clicker:get_meta():set_string("play_music", "1")
end end
end, end,
@ -115,50 +115,50 @@ minetest.register_node("supplemental:loudspeaker", {
}) })
minetest.register_abm({ minetest.register_abm({
nodenames = { "supplemental:loudspeaker" }, nodenames = { "tutorial_supplemental:loudspeaker" },
interval = 5, interval = 5,
chance = 1, chance = 1,
action = set_loudspeaker_infotext, action = set_loudspeaker_infotext,
}) })
minetest.register_craftitem("supplemental:rock", { minetest.register_craftitem("tutorial_supplemental:rock", {
description = S("piece of rock"), description = S("piece of rock"),
inventory_image = "supplemental_rock.png", inventory_image = "supplemental_rock.png",
}) })
minetest.register_craftitem("supplemental:wheat", { minetest.register_craftitem("tutorial_supplemental:wheat", {
description = S("wheat"), description = S("wheat"),
inventory_image = "supplemental_wheat.png", inventory_image = "supplemental_wheat.png",
}) })
minetest.register_craftitem("supplemental:flour", { minetest.register_craftitem("tutorial_supplemental:flour", {
description = S("flour"), description = S("flour"),
inventory_image = "supplemental_flour.png", inventory_image = "supplemental_flour.png",
}) })
-- Crafting example #2 -- Crafting example #2
minetest.register_craft({ minetest.register_craft({
type = "shapeless", type = "shapeless",
output = "supplemental:flour", output = "tutorial_supplemental:flour",
recipe = {"supplemental:wheat", "supplemental:wheat", "supplemental:wheat", "supplemental:wheat"} recipe = {"tutorial_supplemental:wheat", "tutorial_supplemental:wheat", "tutorial_supplemental:wheat", "tutorial_supplemental:wheat"}
}) })
-- Items for crafting examples #1, #4 and #5 -- Items for crafting examples #1, #4 and #5
minetest.register_craftitem("supplemental:paper_white", { minetest.register_craftitem("tutorial_supplemental:paper_white", {
description = S("white sheet of paper"), description = S("white sheet of paper"),
inventory_image = "default_paper.png", inventory_image = "default_paper.png",
groups = { paper = 1 }, groups = { paper = 1 },
}) })
minetest.register_craftitem("supplemental:paper_orange", { minetest.register_craftitem("tutorial_supplemental:paper_orange", {
description = S("orange sheet of paper"), description = S("orange sheet of paper"),
inventory_image = "supplemental_paper_orange.png", inventory_image = "supplemental_paper_orange.png",
groups = { paper = 1 }, groups = { paper = 1 },
}) })
minetest.register_craftitem("supplemental:paper_purple", { minetest.register_craftitem("tutorial_supplemental:paper_purple", {
description = S("purple sheet of paper"), description = S("purple sheet of paper"),
inventory_image = "supplemental_paper_purple.png", inventory_image = "supplemental_paper_purple.png",
groups = { paper = 1 }, groups = { paper = 1 },
}) })
minetest.register_craftitem("supplemental:paper_green", { minetest.register_craftitem("tutorial_supplemental:paper_green", {
description = S("green sheet of paper"), description = S("green sheet of paper"),
inventory_image = "supplemental_paper_green.png", inventory_image = "supplemental_paper_green.png",
groups = { paper = 1 }, groups = { paper = 1 },
@ -176,7 +176,7 @@ minetest.register_craft({
-- 8 viscosity example liquids -- 8 viscosity example liquids
for v=0,7 do for v=0,7 do
minetest.register_node("supplemental:liquid"..v, { minetest.register_node("tutorial_supplemental:liquid"..v, {
description = string.format(S("flowing test liquid %i"), v), description = string.format(S("flowing test liquid %i"), v),
inventory_image = minetest.inventorycube("supplemental_testliquid"..v..".png"), inventory_image = minetest.inventorycube("supplemental_testliquid"..v..".png"),
drawtype = "flowingliquid", drawtype = "flowingliquid",
@ -202,14 +202,14 @@ for v=0,7 do
drop = "", drop = "",
drowning = 1, drowning = 1,
liquidtype = "flowing", liquidtype = "flowing",
liquid_alternative_flowing = "supplemental:liquid"..v, liquid_alternative_flowing = "tutorial_supplemental:liquid"..v,
liquid_alternative_source = "supplemental:liquidsource"..v, liquid_alternative_source = "tutorial_supplemental:liquidsource"..v,
liquid_viscosity = v, liquid_viscosity = v,
groups = {not_in_creative_inventory = 1}, groups = {not_in_creative_inventory = 1},
sounds = default.node_sound_water_defaults(), sounds = default.node_sound_water_defaults(),
}) })
minetest.register_node("supplemental:liquidsource"..v, { minetest.register_node("tutorial_supplemental:liquidsource"..v, {
description = string.format(S("test liquid source %i"), v), description = string.format(S("test liquid source %i"), v),
inventory_image = minetest.inventorycube("supplemental_testliquid"..v..".png"), inventory_image = minetest.inventorycube("supplemental_testliquid"..v..".png"),
drawtype = "liquid", drawtype = "liquid",
@ -229,10 +229,30 @@ for v=0,7 do
drop = "", drop = "",
drowning = 1, drowning = 1,
liquidtype = "source", liquidtype = "source",
liquid_alternative_flowing = "supplemental:liquid"..v, liquid_alternative_flowing = "tutorial_supplemental:liquid"..v,
liquid_alternative_source = "supplemental:liquidsource"..v, liquid_alternative_source = "tutorial_supplemental:liquidsource"..v,
liquid_viscosity = v, liquid_viscosity = v,
groups = {}, groups = {},
sounds = default.node_sound_water_defaults(), sounds = default.node_sound_water_defaults(),
}) })
minetest.register_alias("supplemental:liquid"..v, "tutorial_supplemental:liquid"..v)
minetest.register_alias("supplemental:liquidsource"..v, "tutorial_supplemental:liquidsource"..v)
end end
minetest.register_alias("supplemental:sticky", "tutorial_supplemental:sticky")
minetest.register_alias("supplemental:bouncy", "tutorial_supplemental:bouncy")
minetest.register_alias("supplemental:conglomerate", "tutorial_supplemental:conglomerate")
minetest.register_alias("supplemental:frame", "tutorial_supplemental:frame")
minetest.register_alias("supplemental:spikes", "tutorial_supplemental:spikes")
minetest.register_alias("supplemental:spikes_large", "tutorial_supplemental:spikes_large")
minetest.register_alias("supplemental:loudspeaker", "tutorial_supplemental:loudspeaker")
minetest.register_alias("supplemental:rock", "tutorial_supplemental:rock")
minetest.register_alias("supplemental:wheat", "tutorial_supplemental:wheat")
minetest.register_alias("supplemental:flour", "tutorial_supplemental:flour")
minetest.register_alias("supplemental:paper_white", "tutorial_supplemental:paper_white")
minetest.register_alias("supplemental:paper_orange", "tutorial_supplemental:paper_orange")
minetest.register_alias("supplemental:paper_purple", "tutorial_supplemental:paper_purple")
minetest.register_alias("supplemental:paper_green", "tutorial_supplemental:paper_green")
minetest.register_alias("supplemental:book", "tutorial_supplemental:book")

View File

@ -0,0 +1,3 @@
name = tutorial_supplemental
depends = tutorial_default, tutorial_music
optional_depends = intllib

View File

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 341 B

View File

Before

Width:  |  Height:  |  Size: 621 B

After

Width:  |  Height:  |  Size: 621 B

View File

Before

Width:  |  Height:  |  Size: 335 B

After

Width:  |  Height:  |  Size: 335 B

View File

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

View File

Before

Width:  |  Height:  |  Size: 814 B

After

Width:  |  Height:  |  Size: 814 B

View File

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 391 B

View File

Before

Width:  |  Height:  |  Size: 340 B

After

Width:  |  Height:  |  Size: 340 B

View File

Before

Width:  |  Height:  |  Size: 375 B

After

Width:  |  Height:  |  Size: 375 B

View File

Before

Width:  |  Height:  |  Size: 387 B

After

Width:  |  Height:  |  Size: 387 B

View File

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 376 B

View File

Before

Width:  |  Height:  |  Size: 220 B

After

Width:  |  Height:  |  Size: 220 B

View File

Before

Width:  |  Height:  |  Size: 842 B

After

Width:  |  Height:  |  Size: 842 B

View File

Before

Width:  |  Height:  |  Size: 690 B

After

Width:  |  Height:  |  Size: 690 B

View File

Before

Width:  |  Height:  |  Size: 706 B

After

Width:  |  Height:  |  Size: 706 B

View File

Before

Width:  |  Height:  |  Size: 710 B

After

Width:  |  Height:  |  Size: 710 B

View File

Before

Width:  |  Height:  |  Size: 484 B

After

Width:  |  Height:  |  Size: 484 B

View File

Before

Width:  |  Height:  |  Size: 552 B

After

Width:  |  Height:  |  Size: 552 B

View File

Before

Width:  |  Height:  |  Size: 511 B

After

Width:  |  Height:  |  Size: 511 B

View File

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 448 B

View File

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 492 B

View File

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 547 B