Merge pull request 'Formspec Refactoring' (#2635) from AFCMS/MineClone2:formspec-v4 into master

Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/2635
Reviewed-by: 𝕵𝖔𝖍𝖆𝖓𝖓𝖊𝖘 𝕱𝖗𝖎𝖙𝖟 <mrrar@noreply.git.minetest.land>
Reviewed-by: ancientmarinerdev <ancientmariner_dev@proton.me>
This commit is contained in:
AFCMS 2023-08-26 07:27:25 +00:00
commit f008fa3323
47 changed files with 2413 additions and 1397 deletions

View file

@ -1,3 +1,5 @@
---@diagnostic disable
unused_args = false unused_args = false
allow_defined_top = true allow_defined_top = true
max_line_length = false max_line_length = false

22
.luarc.json Normal file
View file

@ -0,0 +1,22 @@
{
"runtime.version": "LuaJIT",
"diagnostics": { "disable": ["lowercase-global"] },
"diagnostics.globals": [
"minetest",
"dump",
"dump2",
"Raycast",
"Settings",
"PseudoRandom",
"PerlinNoise",
"VoxelManip",
"SecureRandom",
"VoxelArea",
"PerlinNoiseMap",
"PcgRandom",
"ItemStack",
"AreaStore",
"vector"
],
"workspace.ignoreDir": [".luacheckrc"]
}

View file

@ -247,3 +247,12 @@ end)
minetest.register_on_mods_loaded(function() minetest.register_on_mods_loaded(function()
table.sort(mcl_experience.on_add_xp, function(a, b) return a.priority < b.priority end) table.sort(mcl_experience.on_add_xp, function(a, b) return a.priority < b.priority end)
end) end)
mcl_gamemode.register_on_gamemode_change(function(player, old_gamemode, new_gamemode)
if new_gamemode == "survival" then
mcl_experience.setup_hud(player)
mcl_experience.update(player)
elseif new_gamemode == "creative" then
mcl_experience.remove_hud(player)
end
end)

View file

@ -1,3 +1,4 @@
name = mcl_experience name = mcl_experience
author = oilboi author = oilboi
description = eXPerience mod description = eXPerience mod
depends = mcl_gamemode

View file

@ -0,0 +1,40 @@
# MineClone2 Formspec API
## `mcl_formspec.label_color`
Contains the color used for formspec labels, currently `#313131`.
## `mcl_formspec.get_itemslot_bg(x, y, w, h)`
Get the background of inventory slots (formspec version = 1)
ex:
```lua
local formspec = table.concat({
mcl_formspec.get_itemslot_bg(0, 0, 5, 2),
"list[current_player;super_inventory;0,0;5,2;]",
})
```
## `mcl_formspec.get_itemslot_bg_v4(x, y, w, h, size, texture)`
Get the background of inventory slots (formspec version > 1)
Works basically the same as `mcl_formspec.get_itemslot_bg(x, y, w, h)` but have more customisation options:
- `size`: allow you to customize the size of the slot borders, default is 0.05
- `texture`: allow you to specify a custom texture tu use instead of the default one
ex:
```lua
local formspec = table.concat({
mcl_formspec.get_itemslot_bg_v4(0.375, 0.375, 5, 2, 0.1, "super_slot_background.png"),
"list[current_player;super_inventory;0.375,0.375;5,2;]",
})
```
## `mcl_formspec.itemslot_border_size`
Contains the default item slot border size used by `mcl_formspec.get_itemslot_bg_v4`, currently 0.05

View file

@ -0,0 +1,21 @@
# MineClone2 Formspec Guide
**_This guide will teach you the rules for creating formspecs for the MineClone2 game._**
Formspecs are an important part of game and mod development.
First of all, MineClone2 aims to support ONLY last formspec version. Many utility functions will not work with formspec v1 or v2.
The typical width of an 9 slots width inventory formspec is `0.375 + 9 + ((9-1) * 0.25) + 0.375 = 11.75`
Margins are 0.375.
The labels color is `mcl_formspec.label_color`
Space between 1st inventory line and the rest of inventory is 0.45
Labels should have 0.375 space above if there is no other stuff above and 0.45 between content
- 0.375 under
According to minetest modding book, table.concat is faster than string concatenation, so this method should be prefered (the code is also more clear)

View file

@ -1,5 +1,13 @@
mcl_formspec = {} mcl_formspec = {}
mcl_formspec.label_color = "#313131"
---Get the background of inventory slots (formspec version = 1)
---@param x number
---@param y number
---@param w number
---@param h number
---@return string
function mcl_formspec.get_itemslot_bg(x, y, w, h) function mcl_formspec.get_itemslot_bg(x, y, w, h)
local out = "" local out = ""
for i = 0, w - 1, 1 do for i = 0, w - 1, 1 do
@ -9,3 +17,40 @@ function mcl_formspec.get_itemslot_bg(x, y, w, h)
end end
return out return out
end end
---This function will replace mcl_formspec.get_itemslot_bg then every formspec will be upgrade to version 4
---@param x number
---@param y number
---@param size number
---@param texture? string
---@return string
---@nodiscard
local function get_slot(x, y, size, texture)
local t = "image[" .. x - size .. "," .. y - size .. ";" .. 1 + (size * 2) ..
"," .. 1 + (size * 2) .. ";" .. (texture and texture or "mcl_formspec_itemslot.png") .. "]"
return t
end
mcl_formspec.itemslot_border_size = 0.05
---Get the background of inventory slots (formspec version > 1)
---@param x number
---@param y number
---@param w integer
---@param h integer
---@param size? number Optional size of the slot border (default: 0.05)
---@param texture? string Optional texture to replace the default one
---@return string
---@nodiscard
function mcl_formspec.get_itemslot_bg_v4(x, y, w, h, size, texture)
if not size then
size = mcl_formspec.itemslot_border_size
end
local out = ""
for i = 0, w - 1, 1 do
for j = 0, h - 1, 1 do
out = out .. get_slot(x + i + (i * 0.25), y + j + (j * 0.25), size, texture)
end
end
return out
end

View file

@ -0,0 +1,35 @@
# `mcl_inventory`
## `mcl_inventory.register_survival_inventory_tab(def)`
```lua
mcl_inventory.register_survival_inventory_tab({
-- Page identifier
-- Used to uniquely identify the tab
id = "test",
-- The tab description, can be translated
description = "Test",
-- The name of the item that will be used as icon
item_icon = "mcl_core:stone",
-- If true, the main inventory will be shown at the bottom of the tab
-- Listrings need to be added by hand
show_inventory = true,
-- This function must return the tab's formspec for the player
build = function(player)
return "label[1,1;Hello hello]button[2,2;2,2;Hello;hey]"
end,
-- This function will be called in the on_player_receive_fields callback if the tab is currently open
handle = function(player, fields)
print(dump(fields))
end,
-- This function will be called to know if a player can see the tab
-- Returns true by default
access = function(player)
end,
```

View file

@ -3,19 +3,35 @@ local F = minetest.formspec_escape
local C = minetest.colorize local C = minetest.colorize
-- Prepare player info table -- Prepare player info table
---@type table<string, {page: string, filter: string, start_i: integer, inv_size: integer}>
local players = {} local players = {}
-- Containing all the items for each Creative Mode tab -- Containing all the items for each Creative Mode tab
---@type table<string, string[]>
local inventory_lists = {} local inventory_lists = {}
--local mod_player = minetest.get_modpath("mcl_player")
-- Create tables -- Create tables
local builtin_filter_ids = {"blocks","deco","redstone","rail","food","tools","combat","mobs","brew","matr","misc","all"} ---@type string[]
local builtin_filter_ids = {
"blocks",
"deco",
"redstone",
"rail",
"food",
"tools",
"combat",
"mobs",
"brew",
"matr",
"misc",
"all"
}
for _, f in pairs(builtin_filter_ids) do for _, f in pairs(builtin_filter_ids) do
inventory_lists[f] = {} inventory_lists[f] = {}
end end
---@param tbl string[]
local function replace_enchanted_books(tbl) local function replace_enchanted_books(tbl)
for k, item in ipairs(tbl) do for k, item in ipairs(tbl) do
if item:find("mcl_enchanting:book_enchanted") == 1 then if item:find("mcl_enchanting:book_enchanted") == 1 then
@ -28,20 +44,32 @@ local function replace_enchanted_books(tbl)
end end
end end
--[[ Populate all the item tables. We only do this once. Note this code must be -- Populate all the item tables. We only do this once.
executed after loading all the other mods in order to work. ]] -- Note this code must be executed after loading all the other mods in order to work.
minetest.register_on_mods_loaded(function() minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0) and def.description and def.description ~= "" then if (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0) and def.description and
def.description ~= "" then
---@param def mt.ItemDef|mt.NodeDef
local function is_redstone(def) local function is_redstone(def)
return def.mesecons or def.groups.mesecon or def.groups.mesecon_conductor_craftable or def.groups.mesecon_effecor_off return def.mesecons or def.groups.mesecon or def.groups.mesecon_conductor_craftable or
def.groups.mesecon_effecor_off
end end
---@param def mt.ItemDef|mt.NodeDef
local function is_tool(def) local function is_tool(def)
return def.groups.tool or (def.tool_capabilities and def.tool_capabilities.damage_groups == nil) return def.groups.tool or (def.tool_capabilities and def.tool_capabilities.damage_groups == nil)
end end
---@param def mt.ItemDef|mt.NodeDef
local function is_weapon_or_armor(def) local function is_weapon_or_armor(def)
return def.groups.weapon or def.groups.weapon_ranged or def.groups.ammo or def.groups.combat_item or ((def.groups.armor_head or def.groups.armor_torso or def.groups.armor_legs or def.groups.armor_feet or def.groups.horse_armor) and def.groups.non_combat_armor ~= 1) return def.groups.weapon or def.groups.weapon_ranged or def.groups.ammo or def.groups.combat_item or
(
(
def.groups.armor_head or def.groups.armor_torso or def.groups.armor_legs or def.groups.armor_feet or
def.groups.horse_armor) and def.groups.non_combat_armor ~= 1)
end end
-- Is set to true if it was added in any category besides misc -- Is set to true if it was added in any category besides misc
local nonmisc = false local nonmisc = false
if def.groups.building_block then if def.groups.building_block then
@ -110,6 +138,11 @@ minetest.register_on_mods_loaded(function()
end end
end) end)
---@param name string
---@param description string
---@param lang mt.LangCode
---@param filter string
---@return integer
local function filter_item(name, description, lang, filter) local function filter_item(name, description, lang, filter)
local desc local desc
if not lang then if not lang then
@ -120,13 +153,16 @@ local function filter_item(name, description, lang, filter)
return string.find(name, filter, nil, true) or string.find(desc, filter, nil, true) return string.find(name, filter, nil, true) or string.find(desc, filter, nil, true)
end end
---@param filter string
---@param player mt.PlayerObjectRef
local function set_inv_search(filter, player) local function set_inv_search(filter, player)
local playername = player:get_player_name() local playername = player:get_player_name()
local inv = minetest.get_inventory({ type = "detached", name = "creative_" .. playername }) local inv = minetest.get_inventory({ type = "detached", name = "creative_" .. playername })
local creative_list = {} local creative_list = {}
local lang = minetest.get_player_information(playername).lang_code local lang = minetest.get_player_information(playername).lang_code
for name, def in pairs(minetest.registered_items) do for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0) and def.description and def.description ~= "" then if (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0) and def.description and
def.description ~= "" then
if filter_item(string.lower(def.name), def.description, lang, filter) then if filter_item(string.lower(def.name), def.description, lang, filter) then
table.insert(creative_list, name) table.insert(creative_list, name)
end end
@ -147,6 +183,8 @@ local function set_inv_search(filter, player)
inv:set_list("main", creative_list) inv:set_list("main", creative_list)
end end
---@param page string
---@param player mt.PlayerObjectRef
local function set_inv_page(page, player) local function set_inv_page(page, player)
local playername = player:get_player_name() local playername = player:get_player_name()
local inv = minetest.get_inventory({ type = "detached", name = "creative_" .. playername }) local inv = minetest.get_inventory({ type = "detached", name = "creative_" .. playername })
@ -160,6 +198,8 @@ local function set_inv_page(page, player)
inv:set_list("main", creative_list) inv:set_list("main", creative_list)
end end
---@param player mt.PlayerObjectRef
local function init(player) local function init(player)
local playername = player:get_player_name() local playername = player:get_player_name()
minetest.create_detached_inventory("creative_" .. playername, { minetest.create_detached_inventory("creative_" .. playername, {
@ -197,24 +237,45 @@ local trash = minetest.create_detached_inventory("trash", {
inv:set_stack(listname, index, "") inv:set_stack(listname, index, "")
end, end,
}) })
trash:set_size("main", 1) trash:set_size("main", 1)
local noffset = {} -- numeric tab offset ------------------------------
local offset = {} -- string offset: -- Formspec Precalculations --
local boffset = {} -- ------------------------------
local hoch = {}
local filtername = {}
--local bg = {}
local noffset_x_start = -0.24 -- Numeric position of tab background image, indexed by tab name
---@type table<string, {[0]: number, [1]: number}>
local noffset = {}
-- String position of tab button background image, indexed by tab name
---@type table<string, string>
local offset = {}
-- String position of tab button, indexed by tab name
---@type table<string, string>
local boffset = {}
-- Used to determine the tab button background image
---@type table<string, ""|"_down">
local button_bg_postfix = {}
-- Tab caption/tooltip translated string, indexed by tab name
---@type table<string, string>
local filtername = {}
local noffset_x_start = 0.2
local noffset_x = noffset_x_start local noffset_x = noffset_x_start
local noffset_y = -0.25 local noffset_y = -1.34
---@param id string
---@param right? boolean
local function next_noffset(id, right) local function next_noffset(id, right)
if right then if right then
noffset[id] = { 8.94, noffset_y } noffset[id] = { 11.3, noffset_y }
else else
noffset[id] = { noffset_x, noffset_y } noffset[id] = { noffset_x, noffset_y }
noffset_x = noffset_x + 1.25 noffset_x = noffset_x + 1.6
end end
end end
@ -228,7 +289,7 @@ next_noffset("misc")
next_noffset("nix", true) next_noffset("nix", true)
noffset_x = noffset_x_start noffset_x = noffset_x_start
noffset_y = 8.12 noffset_y = 8.64
-- Lower row -- Lower row
next_noffset("food") next_noffset("food")
@ -240,23 +301,23 @@ next_noffset("inv", true)
for k, v in pairs(noffset) do for k, v in pairs(noffset) do
offset[k] = tostring(v[1]) .. "," .. tostring(v[2]) offset[k] = tostring(v[1]) .. "," .. tostring(v[2])
boffset[k] = tostring(v[1]+0.19) .. "," .. tostring(v[2]+0.25) boffset[k] = tostring(v[1] + 0.24) .. "," .. tostring(v[2] + 0.25)
end end
hoch["blocks"] = "" button_bg_postfix["blocks"] = ""
hoch["deco"] = "" button_bg_postfix["deco"] = ""
hoch["redstone"] = "" button_bg_postfix["redstone"] = ""
hoch["rail"] = "" button_bg_postfix["rail"] = ""
hoch["brew"] = "" button_bg_postfix["brew"] = ""
hoch["misc"] = "" button_bg_postfix["misc"] = ""
hoch["nix"] = "" button_bg_postfix["nix"] = ""
hoch["default"] = "" button_bg_postfix["default"] = ""
hoch["food"] = "_down" button_bg_postfix["food"] = "_down"
hoch["tools"] = "_down" button_bg_postfix["tools"] = "_down"
hoch["combat"] = "_down" button_bg_postfix["combat"] = "_down"
hoch["mobs"] = "_down" button_bg_postfix["mobs"] = "_down"
hoch["matr"] = "_down" button_bg_postfix["matr"] = "_down"
hoch["inv"] = "_down" button_bg_postfix["inv"] = "_down"
filtername["blocks"] = S("Building Blocks") filtername["blocks"] = S("Building Blocks")
filtername["deco"] = S("Decoration Blocks") filtername["deco"] = S("Decoration Blocks")
@ -291,120 +352,8 @@ filtername["inv"] = S("Survival Inventory")
bg["default"] = dark_bg bg["default"] = dark_bg
end]] end]]
local function get_stack_size(player) -- Item name representing a tab, indexed by tab name
return player:get_meta():get_int("mcl_inventory:switch_stack") ---@type table<string, string>
end
local function set_stack_size(player, n)
player:get_meta():set_int("mcl_inventory:switch_stack", n)
end
minetest.register_on_joinplayer(function (player)
if get_stack_size(player) == 0 then
set_stack_size(player, 64)
end
end)
function mcl_inventory.set_creative_formspec(player)
local playername = player:get_player_name()
if not players[playername] then return end
local start_i = players[playername].start_i
local pagenum = start_i / (9*5) + 1
local name = players[playername].page
local inv_size = players[playername].inv_size
local filter = players[playername].filter
local pagemax = math.max(1, math.floor((inv_size-1) / (9*5) + 1))
local main_list
local listrings = "listring[detached:creative_"..playername..";main]"..
"listring[current_player;main]"..
"listring[detached:trash;main]"
local inv_bg = "crafting_inventory_creative.png"
if name == "inv" then
inv_bg = "crafting_inventory_creative_survival.png"
-- Background images for armor slots (hide if occupied)
local armor_slot_imgs = ""
local inv = player:get_inventory()
if inv:get_stack("armor", 2):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[2.5,1.3;1,1;mcl_inventory_empty_armor_slot_helmet.png]"
end
if inv:get_stack("armor", 3):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[2.5,2.75;1,1;mcl_inventory_empty_armor_slot_chestplate.png]"
end
if inv:get_stack("armor", 4):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[5.5,1.3;1,1;mcl_inventory_empty_armor_slot_leggings.png]"
end
if inv:get_stack("armor", 5):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[5.5,2.75;1,1;mcl_inventory_empty_armor_slot_boots.png]"
end
if inv:get_stack("offhand", 1):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[1.5,2.025;1,1;mcl_inventory_empty_armor_slot_shield.png]"
end
local stack_size = get_stack_size(player)
-- Survival inventory slots
main_list = "list[current_player;main;0,3.75;9,3;9]" ..
mcl_formspec.get_itemslot_bg(0, 3.75, 9, 3) ..
-- Armor
"list[current_player;armor;2.5,1.3;1,1;1]" ..
"list[current_player;armor;2.5,2.75;1,1;2]" ..
"list[current_player;armor;5.5,1.3;1,1;3]" ..
"list[current_player;armor;5.5,2.75;1,1;4]" ..
mcl_formspec.get_itemslot_bg(2.5, 1.3, 1, 1) ..
mcl_formspec.get_itemslot_bg(2.5, 2.75, 1, 1) ..
mcl_formspec.get_itemslot_bg(5.5, 1.3, 1, 1) ..
mcl_formspec.get_itemslot_bg(5.5, 2.75, 1, 1) ..
"list[current_player;offhand;1.5,2.025;1,1]" ..
mcl_formspec.get_itemslot_bg(1.5, 2.025, 1, 1) ..
armor_slot_imgs ..
-- Player preview
mcl_player.get_player_formspec_model(player, 3.9, 1.4, 1.2333, 2.4666, "") ..
-- Crafting guide button
"image_button[9,1;1,1;craftguide_book.png;__mcl_craftguide;]" ..
"tooltip[__mcl_craftguide;"..F(S("Recipe book")) .. "]" ..
-- Help button
"image_button[9,2;1,1;doc_button_icon_lores.png;__mcl_doc;]" ..
"tooltip[__mcl_doc;" .. F(S("Help")) .. "]" ..
-- Achievements button
"image_button[9,3;1,1;mcl_achievements_button.png;__mcl_achievements;]" ..
--"style_type[image_button;border=;bgimg=;bgimg_pressed=]" ..
"tooltip[__mcl_achievements;"..F(S("Advancements")) .. "]" ..
-- Switch stack size button
"image_button[9,4;1,1;default_apple.png;__switch_stack;]" ..
"label[9.4,4.4;" .. F(C("#FFFFFF", stack_size ~= 1 and stack_size or "")) .. "]" ..
"tooltip[__switch_stack;" .. F(S("Switch stack size")) .. "]"
-- Skins button
if minetest.global_exists("mcl_skins") then
main_list = main_list ..
"image_button[9,5;1,1;mcl_skins_button.png;__mcl_skins;]" ..
"tooltip[__mcl_skins;"..F(S("Select player skin")) .. "]"
end
-- For shortcuts
listrings = listrings ..
"listring[detached:"..playername.."_armor;armor]"..
"listring[current_player;main]"
else
-- Creative inventory slots
main_list = "list[detached:creative_"..playername..";main;0,1.75;9,5;"..tostring(start_i).."]"..
mcl_formspec.get_itemslot_bg(0,1.75,9,5)..
-- Page buttons
"label[9.0,5.5;"..F(S("@1/@2", pagenum, pagemax)).."]"..
"image_button[9.0,6.0;0.7,0.7;crafting_creative_prev.png;creative_prev;]"..
"image_button[9.5,6.0;0.7,0.7;crafting_creative_next.png;creative_next;]"
end
local tab_icon = { local tab_icon = {
blocks = "mcl_core:brick_block", blocks = "mcl_core:brick_block",
deco = "mcl_flowers:peony", deco = "mcl_flowers:peony",
@ -420,66 +369,233 @@ function mcl_inventory.set_creative_formspec(player)
matr = "mcl_core:stick", matr = "mcl_core:stick",
inv = "mcl_chests:chest", inv = "mcl_chests:chest",
} }
-- Get the player configured stack size when taking items from creative inventory
---@param player mt.PlayerObjectRef
---@return integer
local function get_stack_size(player)
return player:get_meta():get_int("mcl_inventory:switch_stack")
end
-- Set the player configured stack size when taking items from creative inventory
---@param player mt.PlayerObjectRef
---@param n integer
local function set_stack_size(player, n)
player:get_meta():set_int("mcl_inventory:switch_stack", n)
end
minetest.register_on_joinplayer(function(player)
if get_stack_size(player) == 0 then
set_stack_size(player, 64)
end
end)
---@param player mt.PlayerObjectRef
function mcl_inventory.set_creative_formspec(player)
local playername = player:get_player_name()
if not players[playername] then return end
local start_i = players[playername].start_i
local pagenum = start_i / (9 * 5) + 1
local page = players[playername].page
local inv_size = players[playername].inv_size
local filter = players[playername].filter
if not inv_size then
if page == "nix" then
local inv = minetest.get_inventory({ type = "detached", name = "creative_" .. playername })
inv_size = inv:get_size("main")
elseif page and page ~= "inv" then
inv_size = #(inventory_lists[page])
else
inv_size = 0
end
end
local pagemax = math.max(1, math.floor((inv_size - 1) / (9 * 5) + 1))
local name = "nix"
local main_list
local listrings = table.concat({
"listring[detached:creative_" .. playername .. ";main]",
"listring[current_player;main]",
"listring[detached:trash;main]",
})
if page then
name = page
if players[playername] then
players[playername].page = page
end
end
if name == "inv" then
-- Background images for armor slots (hide if occupied)
local armor_slot_imgs = ""
local inv = player:get_inventory()
if inv:get_stack("armor", 2):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[3.5,0.375;1,1;mcl_inventory_empty_armor_slot_helmet.png]"
end
if inv:get_stack("armor", 3):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[3.5,2.125;1,1;mcl_inventory_empty_armor_slot_chestplate.png]"
end
if inv:get_stack("armor", 4):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[7.25,0.375;1,1;mcl_inventory_empty_armor_slot_leggings.png]"
end
if inv:get_stack("armor", 5):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[7.25,2.125;1,1;mcl_inventory_empty_armor_slot_boots.png]"
end
if inv:get_stack("offhand", 1):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[2.25,1.25;1,1;mcl_inventory_empty_armor_slot_shield.png]"
end
local stack_size = get_stack_size(player)
-- Survival inventory slots
main_list = table.concat({
mcl_formspec.get_itemslot_bg_v4(0.375, 3.375, 9, 3),
"list[current_player;main;0.375,3.375;9,3;9]",
-- Armor
mcl_formspec.get_itemslot_bg_v4(3.5, 0.375, 1, 1),
mcl_formspec.get_itemslot_bg_v4(3.5, 2.125, 1, 1),
mcl_formspec.get_itemslot_bg_v4(7.25, 0.375, 1, 1),
mcl_formspec.get_itemslot_bg_v4(7.25, 2.125, 1, 1),
"list[current_player;armor;3.5,0.375;1,1;1]",
"list[current_player;armor;3.5,2.125;1,1;2]",
"list[current_player;armor;7.25,0.375;1,1;3]",
"list[current_player;armor;7.25,2.125;1,1;4]",
-- Offhand
mcl_formspec.get_itemslot_bg_v4(2.25, 1.25, 1, 1),
"list[current_player;offhand;2.25,1.25;1,1]",
armor_slot_imgs,
-- Player preview
"image[4.75,0.33;2.25,2.83;mcl_inventory_background9.png;2]",
mcl_player.get_player_formspec_model(player, 4.75, 0.45, 2.25, 2.75, ""),
-- Crafting guide button
"image_button[11.575,0.825;1.1,1.1;craftguide_book.png;__mcl_craftguide;]",
"tooltip[__mcl_craftguide;" .. F(S("Recipe book")) .. "]",
-- Help button
"image_button[11.575,2.075;1.1,1.1;doc_button_icon_lores.png;__mcl_doc;]",
"tooltip[__mcl_doc;" .. F(S("Help")) .. "]",
-- Advancements button
"image_button[11.575,3.325;1.1,1.1;mcl_achievements_button.png;__mcl_achievements;]",
--"style_type[image_button;border=;bgimg=;bgimg_pressed=]",
"tooltip[__mcl_achievements;" .. F(S("Advancements")) .. "]",
-- Switch stack size button
"image_button[11.575,4.575;1.1,1.1;default_apple.png;__switch_stack;]",
"label[12.275,5.35;" .. F(C("#FFFFFF", tostring(stack_size ~= 1 and stack_size or ""))) .. "]",
"tooltip[__switch_stack;" .. F(S("Switch stack size")) .. "]",
-- Skins button
"image_button[11.575,5.825;1.1,1.1;mcl_skins_button.png;__mcl_skins;]",
"tooltip[__mcl_skins;" .. F(S("Select player skin")) .. "]",
})
-- For shortcuts
listrings = listrings ..
"listring[detached:" .. playername .. "_armor;armor]" ..
"listring[current_player;main]"
else
--local nb_lines = math.ceil(inv_size / 9)
-- Creative inventory slots
main_list = table.concat({
mcl_formspec.get_itemslot_bg_v4(0.375, 0.875, 9, 5),
-- Basic code to replace buttons by scrollbar
-- Require Minetest 5.8
--
--"scroll_container[0.375,0.875;11.575,6;scroll;vertical;1.25]",
--"list[detached:creative_" .. playername .. ";main;0,0;9," .. nb_lines .. ";]",
--"scroll_container_end[]",
--"scrollbaroptions[min=0;max=" .. math.max(nb_lines - 5, 0) .. ";smallstep=1;largesteps=1;arrows=hide]",
--"scrollbar[11.75,0.825;0.75,6.1;vertical;scroll;0]",
"list[detached:creative_" .. playername .. ";main;0.375,0.875;9,5;" .. tostring(start_i) .. "]",
-- Page buttons
"label[11.65,4.33;" .. F(S("@1 / @2", pagenum, pagemax)) .. "]",
"image_button[11.575,4.58;1.1,1.1;crafting_creative_prev.png^[transformR270;creative_prev;]",
"image_button[11.575,5.83;1.1,1.1;crafting_creative_next.png^[transformR270;creative_next;]",
})
end
---@param current_tab string
---@param this_tab string
---@return string
local function tab(current_tab, this_tab) local function tab(current_tab, this_tab)
local bg_img local bg_img
if current_tab == this_tab then if current_tab == this_tab then
bg_img = "crafting_creative_active"..hoch[this_tab]..".png" bg_img = "crafting_creative_active" .. button_bg_postfix[this_tab] .. ".png"
else else
bg_img = "crafting_creative_inactive"..hoch[this_tab]..".png" bg_img = "crafting_creative_inactive" .. button_bg_postfix[this_tab] .. ".png"
end end
return return table.concat({
"style["..this_tab..";border=false;bgimg=;bgimg_pressed=]".. "style[" .. this_tab .. ";border=false;bgimg=;bgimg_pressed=;noclip=true]",
"item_image_button[" .. boffset[this_tab] ..";1,1;"..tab_icon[this_tab]..";"..this_tab..";]".. "image[" .. offset[this_tab] .. ";1.5,1.44;" .. bg_img .. "]",
"image[" .. offset[this_tab] .. ";1.5,1.44;" .. bg_img .. "]" "item_image_button[" .. boffset[this_tab] .. ";1,1;" .. tab_icon[this_tab] .. ";" .. this_tab .. ";]",
"tooltip[blocks;" .. F(filtername[this_tab]) .. "]"
})
end end
local caption = "" local caption = ""
if name ~= "inv" and filtername[name] then if name ~= "inv" and filtername[name] then
caption = "label[0,1.2;"..F(minetest.colorize("#313131", filtername[name])).."]" caption = "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, filtername[name])) .. "]"
end end
local formspec = "size[10,9.3]".. local formspec = table.concat({
"no_prepend[]".. "formspec_version[6]",
mcl_vars.gui_nonbg..mcl_vars.gui_bg_color.. "size[13,8.75]",
"background[-0.19,-0.25;10.5,9.87;"..inv_bg.."]"..
"label[-5,-5;"..name.."]".. "style_type[image;noclip=true]",
tab(name, "blocks") ..
"tooltip[blocks;"..F(filtername["blocks"]).."]".. -- Hotbar
tab(name, "deco") .. mcl_formspec.get_itemslot_bg_v4(0.375, 7.375, 9, 1),
"tooltip[deco;"..F(filtername["deco"]).."]".. "list[current_player;main;0.375,7.375;9,1;]",
tab(name, "redstone") ..
"tooltip[redstone;"..F(filtername["redstone"]).."]".. -- Trash
tab(name, "rail") .. mcl_formspec.get_itemslot_bg_v4(11.625, 7.375, 1, 1, nil, "crafting_creative_trash.png"),
"tooltip[rail;"..F(filtername["rail"]).."]".. "list[detached:trash;main;11.625,7.375;1,1;]",
tab(name, "misc") ..
"tooltip[misc;"..F(filtername["misc"]).."]".. main_list,
tab(name, "nix") ..
"tooltip[nix;"..F(filtername["nix"]).."]".. caption,
caption..
"list[current_player;main;0,7;9,1;]".. listrings,
mcl_formspec.get_itemslot_bg(0,7,9,1)..
main_list.. tab(name, "blocks"),
tab(name, "food") .. tab(name, "deco"),
"tooltip[food;"..F(filtername["food"]).."]".. tab(name, "redstone"),
tab(name, "tools") .. tab(name, "rail"),
"tooltip[tools;"..F(filtername["tools"]).."]".. tab(name, "misc"),
tab(name, "combat") .. tab(name, "nix"),
"tooltip[combat;"..F(filtername["combat"]).."]"..
tab(name, "mobs") .. tab(name, "food"),
"tooltip[mobs;"..F(filtername["mobs"]).."]".. tab(name, "tools"),
tab(name, "brew") .. tab(name, "combat"),
"tooltip[brew;"..F(filtername["brew"]).."]".. tab(name, "mobs"),
tab(name, "matr") .. tab(name, "brew"),
"tooltip[matr;"..F(filtername["matr"]).."]".. tab(name, "matr"),
tab(name, "inv") .. tab(name, "inv"),
"tooltip[inv;"..F(filtername["inv"]).."]".. })
"list[detached:trash;main;9,7;1,1;]"..
mcl_formspec.get_itemslot_bg(9,7,1,1)..
"image[9,7;1,1;crafting_creative_trash.png]"..
listrings
if name == "nix" then if name == "nix" then
formspec = formspec .. "field[5.3,1.34;4,0.75;search;;"..minetest.formspec_escape(filter).."]" if filter == nil then
formspec = formspec .. "field_close_on_enter[search;false]" filter = ""
end
formspec = formspec .. table.concat({
"field[5.325,0.15;6.1,0.6;search;;" .. minetest.formspec_escape(filter) .. "]",
"field_close_on_enter[search;false]",
"set_focus[search;true]",
})
end end
if pagenum then formspec = formspec .. "p" .. tostring(pagenum) end if pagenum then formspec = formspec .. "p" .. tostring(pagenum) end
player:set_inventory_formspec(formspec) player:set_inventory_formspec(formspec)
@ -609,11 +725,34 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
mcl_inventory.set_creative_formspec(player) mcl_inventory.set_creative_formspec(player)
end) end)
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack) minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack)
return placer and placer:is_player() and minetest.is_creative_enabled(placer:get_player_name()) return placer and placer:is_player() and minetest.is_creative_enabled(placer:get_player_name())
end) end)
if minetest.is_creative_enabled("") then
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack)
-- Place infinite nodes, except for shulker boxes
local group = minetest.get_item_group(itemstack:get_name(), "shulker_box")
return group == 0 or group == nil
end)
function minetest.handle_node_drops(pos, drops, digger)
if not digger or not digger:is_player() then
for _, item in ipairs(drops) do
minetest.add_item(pos, item)
end
end
local inv = digger:get_inventory()
if inv then
for _, item in ipairs(drops) do
if not inv:contains_item("main", item, true) then
inv:add_item("main", item)
end
end
end
end
end
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
-- Initialize variables and inventory -- Initialize variables and inventory
local name = player:get_player_name() local name = player:get_player_name()
@ -629,7 +768,8 @@ minetest.register_on_joinplayer(function(player)
end) end)
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info) minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
if minetest.is_creative_enabled(player:get_player_name()) and get_stack_size(player) == 64 and action == "put" and inventory_info.listname == "main" then if minetest.is_creative_enabled(player:get_player_name()) and get_stack_size(player) == 64 and action == "put" and
inventory_info.listname == "main" then
local stack = inventory_info.stack local stack = inventory_info.stack
stack:set_count(stack:get_stack_max()) stack:set_count(stack:get_stack_max())
player:get_inventory():set_stack("main", inventory_info.index, stack) player:get_inventory():set_stack("main", inventory_info.index, stack)

View file

@ -1,13 +1,17 @@
local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
mcl_inventory = {} mcl_inventory = {}
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/creative.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/survival.lua")
--local mod_player = minetest.get_modpath("mcl_player") --local mod_player = minetest.get_modpath("mcl_player")
--local mod_craftguide = minetest.get_modpath("mcl_craftguide") --local mod_craftguide = minetest.get_modpath("mcl_craftguide")
-- Returns a single itemstack in the given inventory to the main inventory, or drop it when there's no space left ---Returns a single itemstack in the given inventory to the main inventory, or drop it when there's no space left.
function return_item(itemstack, dropper, pos, inv) ---@param itemstack mt.ItemStack
---@param dropper mt.ObjectRef
---@param pos mt.Vector
---@param inv mt.InvRef
local function return_item(itemstack, dropper, pos, inv)
if dropper:is_player() then if dropper:is_player() then
-- Return to main inventory -- Return to main inventory
if inv:room_for_item("main", itemstack) then if inv:room_for_item("main", itemstack) then
@ -15,7 +19,7 @@ function return_item(itemstack, dropper, pos, inv)
else else
-- Drop item on the ground -- Drop item on the ground
local v = dropper:get_look_dir() local v = dropper:get_look_dir()
local p = {x=pos.x, y=pos.y+1.2, z=pos.z} local p = vector.offset(pos, 0, 1.2, 0)
p.x = p.x + (math.random(1, 3) * 0.2) p.x = p.x + (math.random(1, 3) * 0.2)
p.z = p.z + (math.random(1, 3) * 0.2) p.z = p.z + (math.random(1, 3) * 0.2)
local obj = minetest.add_item(p, itemstack) local obj = minetest.add_item(p, itemstack)
@ -34,9 +38,12 @@ function return_item(itemstack, dropper, pos, inv)
return itemstack return itemstack
end end
-- Return items in the given inventory list (name) to the main inventory, or drop them if there is no space left ---Return items in the given inventory list (name) to the main inventory, or drop them if there is no space left.
function return_fields(player, name) ---@param player mt.PlayerObjectRef
---@param name string
local function return_fields(player, name)
local inv = player:get_inventory() local inv = player:get_inventory()
local list = inv:get_list(name) local list = inv:get_list(name)
if not list then return end if not list then return end
for i, stack in ipairs(list) do for i, stack in ipairs(list) do
@ -46,84 +53,20 @@ function return_fields(player, name)
end end
end end
local function set_inventory(player) ---@param player mt.PlayerObjectRef
---@param armor_change_only? boolean
local function set_inventory(player, armor_change_only)
if minetest.is_creative_enabled(player:get_player_name()) then if minetest.is_creative_enabled(player:get_player_name()) then
mcl_inventory.set_creative_formspec(player) if armor_change_only then
-- Stay on survival inventory plage if only the armor has been changed
mcl_inventory.set_creative_formspec(player, 0, 0, nil, nil, "inv")
else
mcl_inventory.set_creative_formspec(player, 0, 1)
end
return return
end end
local inv = player:get_inventory()
inv:set_width("craft", 2)
inv:set_size("craft", 4)
local armor_slots = {"helmet", "chestplate", "leggings", "boots"} player:set_inventory_formspec(mcl_inventory.build_survival_formspec(player))
local armor_slot_imgs = ""
for a=1,4 do
if inv:get_stack("armor", a+1):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[0,"..(a-1)..";1,1;mcl_inventory_empty_armor_slot_"..armor_slots[a]..".png]"
end
end
if inv:get_stack("offhand", 1):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[3,2;1,1;mcl_inventory_empty_armor_slot_shield.png]"
end
local form = "size[9,8.75]" ..
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]" ..
mcl_player.get_player_formspec_model(player, 1.0, 0.0, 2.25, 4.5, "") ..
-- Armor
"list[current_player;armor;0,0;1,1;1]" ..
"list[current_player;armor;0,1;1,1;2]" ..
"list[current_player;armor;0,2;1,1;3]" ..
"list[current_player;armor;0,3;1,1;4]" ..
mcl_formspec.get_itemslot_bg(0,0,1,1) ..
mcl_formspec.get_itemslot_bg(0,1,1,1) ..
mcl_formspec.get_itemslot_bg(0,2,1,1) ..
mcl_formspec.get_itemslot_bg(0,3,1,1) ..
"list[current_player;offhand;3,2;1,1]" ..
mcl_formspec.get_itemslot_bg(3,2,1,1) ..
armor_slot_imgs ..
-- Craft and inventory
"label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))) .. "]" ..
"list[current_player;main;0,4.5;9,3;9]" ..
"list[current_player;main;0,7.74;9,1;]" ..
"label[4,0.5;"..F(minetest.colorize("#313131", S("Crafting"))) .. "]" ..
"list[current_player;craft;4,1;2,2]" ..
"list[current_player;craftpreview;7,1.5;1,1;]" ..
mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3) ..
mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1) ..
mcl_formspec.get_itemslot_bg(4, 1,2, 2) ..
mcl_formspec.get_itemslot_bg(7, 1.5, 1, 1) ..
-- Crafting guide button
"image_button[4.5,3;1,1;craftguide_book.png;__mcl_craftguide;]" ..
"tooltip[__mcl_craftguide;"..F(S("Recipe book")) .. "]" ..
-- Help button
"image_button[8,3;1,1;doc_button_icon_lores.png;__mcl_doc;]" ..
"tooltip[__mcl_doc;" .. F(S("Help")) .. "]"
-- Skins button
if minetest.global_exists("mcl_skins") then
form = form ..
"image_button[3,3;1,1;mcl_skins_button.png;__mcl_skins;]" ..
"tooltip[__mcl_skins;" .. F(S("Select player skin")) .. "]"
end
form = form ..
-- Achievements button
"image_button[7,3;1,1;mcl_achievements_button.png;__mcl_achievements;]" ..
"tooltip[__mcl_achievements;" .. F(S("Advancements")) .. "]" ..
-- For shortcuts
"listring[current_player;main]" ..
"listring[current_player;armor]" ..
"listring[current_player;main]" ..
"listring[current_player;craft]" ..
"listring[current_player;main]"
player:set_inventory_formspec(form)
end end
-- Drop items in craft grid and reset inventory on closing -- Drop items in craft grid and reset inventory on closing
@ -138,7 +81,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end end
end) end)
mcl_inventory.update_inventory_formspec = set_inventory
function mcl_inventory.update_inventory_formspec(player)
set_inventory(player)
end
-- Drop crafting grid items on leaving -- Drop crafting grid items on leaving
minetest.register_on_leaveplayer(function(player) minetest.register_on_leaveplayer(function(player)
@ -150,6 +96,7 @@ end)
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
--init inventory --init inventory
local inv = player:get_inventory() local inv = player:get_inventory()
inv:set_width("main", 9) inv:set_width("main", 9)
inv:set_size("main", 36) inv:set_size("main", 36)
inv:set_size("offhand", 1) inv:set_size("offhand", 1)
@ -174,73 +121,18 @@ minetest.register_on_joinplayer(function(player)
return_fields(player, "enchanting_lapis") return_fields(player, "enchanting_lapis")
end) end)
dofile(minetest.get_modpath(minetest.get_current_modname()).."/creative.lua") ---@param player mt.PlayerObjectRef
function mcl_inventory.update_inventory(player)
local player_gamemode = mcl_gamemode.get_gamemode(player)
if player_gamemode == "creative" then
mcl_inventory.set_creative_formspec(player)
elseif player_gamemode == "survival" then
player:set_inventory_formspec(mcl_inventory.build_survival_formspec(player))
end
end
mcl_gamemode.register_on_gamemode_change(function(player, old_gamemode, new_gamemode)
set_inventory(player)
end)
mcl_player.register_on_visual_change(mcl_inventory.update_inventory_formspec) mcl_player.register_on_visual_change(mcl_inventory.update_inventory_formspec)
local mt_is_creative_enabled = minetest.is_creative_enabled
function minetest.is_creative_enabled(name)
if mt_is_creative_enabled(name) then return true end
if not name then return false end
local p = minetest.get_player_by_name(name)
if p then
return p:get_meta():get_string("gamemode") == "creative"
end
return false
end
local function in_table(n,h)
for k,v in pairs(h) do
if v == n then return true end
end
return false
end
local gamemodes = {
"survival",
"creative"
}
function mcl_inventory.player_set_gamemode(p,g)
local m = p:get_meta()
m:set_string("gamemode",g)
if g == "survival" then
mcl_experience.setup_hud(p)
mcl_experience.update(p)
elseif g == "creative" then
mcl_experience.remove_hud(p)
end
mcl_meshhand.update_player(p)
set_inventory(p)
end
minetest.register_chatcommand("gamemode",{
params = S("[<gamemode>] [<player>]"),
description = S("Change gamemode (survival/creative) for yourself or player"),
privs = { server = true },
func = function(n,param)
-- Full input validation ( just for @erlehmann <3 )
local p
local args = param:split(" ")
if args[2] ~= nil then
p = minetest.get_player_by_name(args[2])
n = args[2]
else
p = minetest.get_player_by_name(n)
end
if not p then
return false, S("Player not online")
end
if args[1] ~= nil and not in_table(args[1],gamemodes) then
return false, S("Gamemode " .. args[1] .. " does not exist.")
elseif args[1] ~= nil then
mcl_inventory.player_set_gamemode(p,args[1])
end
--Result message - show effective game mode
local gm = p:get_meta():get_string("gamemode")
if gm == "" then gm = gamemodes[1] end
return true, S("Gamemode for player ")..n..S(": "..gm)
end
})

View file

@ -1,5 +1,5 @@
name = mcl_inventory name = mcl_inventory
author = BlockMen author = BlockMen
description = Adds the player inventory and creative inventory. description = Adds the player inventory and creative inventory.
depends = mcl_init, mcl_formspec, mcl_enchanting, mcl_player depends = mcl_init, mcl_formspec, mcl_enchanting, mcl_gamemode
optional_depends = mcl_armor, mcl_brewing, mcl_potions, mcl_enchanting, mcl_craftguide optional_depends = mcl_armor, mcl_brewing, mcl_potions, mcl_enchanting, mcl_craftguide, mcl_player

View file

@ -0,0 +1,224 @@
---@diagnostic disable need-check-nil
local table = table
local ipairs = ipairs
local S = minetest.get_translator("mcl_inventory")
local F = minetest.formspec_escape
---@type {id: string, description: string, item_icon: string, build: (fun(player: ObjectRef): string), handle: fun(player: ObjectRef, fields: table), access: (fun(player): boolean), show_inventory: boolean}[]
mcl_inventory.registered_survival_inventory_tabs = {}
---@param def {id: string, description: string, item_icon: string, build: (fun(player: ObjectRef): string), handle: fun(player: ObjectRef, fields: table), access: (fun(player): boolean), show_inventory: boolean}
function mcl_inventory.register_survival_inventory_tab(def)
if #mcl_inventory.registered_survival_inventory_tabs == 7 then
error("Too much tabs registered!")
end
assert(def.id)
assert(def.description)
assert(def.item_icon)
assert(def.build)
assert(def.handle)
for _, d in ipairs(mcl_inventory.registered_survival_inventory_tabs) do
assert(d.id ~= def.id, "Another tab exists with the same name!")
end
if not def.access then
function def.access(player)
return true
end
end
if def.show_inventory == nil then
def.show_inventory = true
end
table.insert(mcl_inventory.registered_survival_inventory_tabs, def)
end
local player_current_tab = {}
minetest.register_on_joinplayer(function(player, last_login)
player_current_tab[player] = "main"
end)
minetest.register_on_leaveplayer(function(player, timed_out)
player_current_tab[player] = nil
end)
---@param player ObjectRef
---@param content string
---@param inventory boolean
---@param tabname string
local function build_page(player, content, inventory, tabname)
local tab_buttons = "style_type[image;noclip=true]"
if #mcl_inventory.registered_survival_inventory_tabs ~= 1 then
for i, d in ipairs(mcl_inventory.registered_survival_inventory_tabs) do
local btn_name = "tab_" .. d.id
tab_buttons = tab_buttons .. table.concat({
"style[" .. btn_name .. ";border=false;bgimg=;bgimg_pressed=;noclip=true]",
"image[" ..
(0.2 + (i - 1) * 1.6) ..
",-1.34;1.5,1.44;" .. (tabname == d.id and "crafting_creative_active.png" or "crafting_creative_inactive.png") ..
"]",
"item_image_button[" .. (0.44 + (i - 1) * 1.6) .. ",-1.1;1,1;" .. d.item_icon .. ";" .. btn_name .. ";]",
"tooltip[" .. btn_name .. ";" .. F(d.description) .. "]"
})
end
end
return table.concat({
"formspec_version[6]",
"size[11.75,10.9]",
inventory and table.concat({
--Main inventory
mcl_formspec.get_itemslot_bg_v4(0.375, 5.575, 9, 3),
"list[current_player;main;0.375,5.575;9,3;9]",
--Hotbar
mcl_formspec.get_itemslot_bg_v4(0.375, 9.525, 9, 1),
"list[current_player;main;0.375,9.525;9,1;]"
}) or "",
content,
tab_buttons,
})
end
local main_page_static = table.concat({
--Armor slots
mcl_formspec.get_itemslot_bg_v4(0.375, 0.375, 1, 4),
"list[current_player;armor;0.375,0.375;1,1;1]",
"list[current_player;armor;0.375,1.625;1,1;2]",
"list[current_player;armor;0.375,2.875;1,1;3]",
"list[current_player;armor;0.375,4.125;1,1;4]",
--Player model background
"image[1.57,0.343;3.62,4.85;mcl_inventory_background9.png;2]",
--Offhand
mcl_formspec.get_itemslot_bg_v4(5.375, 4.125, 1, 1),
"list[current_player;offhand;5.375,4.125;1,1]",
--Craft grid
"label[6.61,0.5;" .. F(minetest.colorize(mcl_formspec.label_color, S("Crafting"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(6.625, 0.875, 2, 2),
"list[current_player;craft;6.625,0.875;2,2]",
"image[9.125,1.5;1,1;crafting_formspec_arrow.png]",
mcl_formspec.get_itemslot_bg_v4(10.375, 1.5, 1, 1),
"list[current_player;craftpreview;10.375,1.5;1,1;]",
--Crafting guide button
"image_button[6.575,4.075;1.1,1.1;craftguide_book.png;__mcl_craftguide;]",
"tooltip[__mcl_craftguide;" .. F(S("Recipe book")) .. "]",
--Help button
"image_button[7.825,4.075;1.1,1.1;doc_button_icon_lores.png;__mcl_doc;]",
"tooltip[__mcl_doc;" .. F(S("Help")) .. "]",
--Skins button
"image_button[9.075,4.075;1.1,1.1;mcl_skins_button.png;__mcl_skins;]",
"tooltip[__mcl_skins;" .. F(S("Select player skin")) .. "]",
--Achievements button
"image_button[10.325,4.075;1.1,1.1;mcl_achievements_button.png;__mcl_achievements;]",
"tooltip[__mcl_achievements;" .. F(S("Achievements")) .. "]",
--Listring
"listring[current_player;main]",
"listring[current_player;armor]",
"listring[current_player;main]",
"listring[current_player;craft]",
"listring[current_player;main]",
})
mcl_inventory.register_survival_inventory_tab({
id = "main",
description = "Main Inventory",
item_icon = "mcl_crafting_table:crafting_table",
show_inventory = true,
build = function(player)
local inv = player:get_inventory()
local armor_slots = { "helmet", "chestplate", "leggings", "boots" }
local armor_slot_imgs = ""
for a = 1, 4 do
if inv:get_stack("armor", a + 1):is_empty() then
armor_slot_imgs = armor_slot_imgs ..
"image[0.375," .. (0.375 + (a - 1) * 1.25) .. ";1,1;mcl_inventory_empty_armor_slot_" .. armor_slots[a] .. ".png]"
end
end
if inv:get_stack("offhand", 1):is_empty() then
armor_slot_imgs = armor_slot_imgs .. "image[5.375,4.125;1,1;mcl_inventory_empty_armor_slot_shield.png]"
end
return main_page_static .. armor_slot_imgs .. mcl_player.get_player_formspec_model(player, 1.57, 0.4, 3.62, 4.85, "")
end,
handle = function() end,
})
--[[
mcl_inventory.register_survival_inventory_tab({
id = "test",
description = "Test",
item_icon = "mcl_core:stone",
show_inventory = true,
build = function(player)
return "label[1,1;Hello hello]button[2,2;2,2;Hello;hey]"
end,
handle = function(player, fields)
print(dump(fields))
end,
})]]
---@param player ObjectRef
function mcl_inventory.build_survival_formspec(player)
local inv = player:get_inventory()
inv:set_width("craft", 2)
inv:set_size("craft", 4)
local tab = player_current_tab[player]
local tab_def = nil
for _, d in ipairs(mcl_inventory.registered_survival_inventory_tabs) do
if tab == d.id then
tab_def = d
break
end
end
local form = build_page(player, tab_def.build(player), tab_def.show_inventory, tab)
return form
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "" and #mcl_inventory.registered_survival_inventory_tabs ~= 1 and
mcl_gamemode.get_gamemode(player) == "survival" then
for _, d in ipairs(mcl_inventory.registered_survival_inventory_tabs) do
if fields["tab_" .. d.id] and d.access(player) then
player_current_tab[player] = d.id
mcl_inventory.update_inventory(player)
return
end
end
for _, d in ipairs(mcl_inventory.registered_survival_inventory_tabs) do
if player_current_tab[player] == d.id and d.access(player) then
d.handle(player, fields)
return
end
end
end
end)

View file

@ -8,23 +8,36 @@ All node definitions share a lot of code, so this is the reason why there
are so many weird tables below. are so many weird tables below.
]] ]]
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local C = minetest.colorize
local F = minetest.formspec_escape
-- For after_place_node local dispenser_formspec = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[4.125,0.375;" .. F(C(mcl_formspec.label_color, S("Dispenser"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(4.125, 0.75, 3, 3),
"list[context;main;4.125,0.75;3,3;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[context;main]",
"listring[current_player;main]",
})
---For after_place_node
---@param pos Vector
local function setup_dispenser(pos) local function setup_dispenser(pos)
-- Set formspec and inventory -- Set formspec and inventory
local form = "size[9,8.75]"..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,4.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
"list[current_player;main;0,7.74;9,1;]"..
mcl_formspec.get_itemslot_bg(0,7.74,9,1)..
"label[3,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Dispenser"))).."]"..
"list[context;main;3,0.5;3,3;]"..
mcl_formspec.get_itemslot_bg(3,0.5,3,3)..
"listring[context;main]"..
"listring[current_player;main]"
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", form) meta:set_string("formspec", dispenser_formspec)
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size("main", 9) inv:set_size("main", 9)
end end
@ -88,8 +101,7 @@ local dispenserdef = {
for i = 1, inv:get_size("main") do for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i) local stack = inv:get_stack("main", i)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} minetest.add_item(vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5), stack)
minetest.add_item(p, stack)
end end
end end
meta:from_table(meta2) meta:from_table(meta2)
@ -107,11 +119,11 @@ local dispenserdef = {
dropdir = vector.multiply(minetest.facedir_to_dir(node.param2), -1) dropdir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
droppos = vector.add(pos, dropdir) droppos = vector.add(pos, dropdir)
elseif node.name == "mcl_dispensers:dispenser_up" then elseif node.name == "mcl_dispensers:dispenser_up" then
dropdir = {x=0, y=1, z=0} dropdir = vector.new(0, 1, 0)
droppos = {x=pos.x, y=pos.y+1, z=pos.z} droppos = vector.offset(pos, 0, 1, 0)
elseif node.name == "mcl_dispensers:dispenser_down" then elseif node.name == "mcl_dispensers:dispenser_down" then
dropdir = {x=0, y=-1, z=0} dropdir = vector.new(0, -1, 0)
droppos = {x=pos.x, y=pos.y-1, z=pos.z} droppos = vector.offset(pos, 0, -1, 0)
end end
local dropnode = minetest.get_node(droppos) local dropnode = minetest.get_node(droppos)
local dropnodedef = minetest.registered_nodes[dropnode.name] local dropnodedef = minetest.registered_nodes[dropnode.name]
@ -143,9 +155,10 @@ local dispenserdef = {
-- Armor, mob heads and pumpkins -- Armor, mob heads and pumpkins
if igroups.armor then if igroups.armor then
local droppos_below = {x = droppos.x, y = droppos.y - 1, z = droppos.z} local droppos_below = vector.offset(droppos, 0, -1, 0)
for _, objs in ipairs({minetest.get_objects_inside_radius(droppos, 1), minetest.get_objects_inside_radius(droppos_below, 1)}) do for _, objs in ipairs({ minetest.get_objects_inside_radius(droppos, 1),
minetest.get_objects_inside_radius(droppos_below, 1) }) do
for _, obj in ipairs(objs) do for _, obj in ipairs(objs) do
stack = mcl_armor.equip(stack, obj) stack = mcl_armor.equip(stack, obj)
if stack:is_empty() then if stack:is_empty() then
@ -301,7 +314,8 @@ local horizontal_def = table.copy(dispenserdef)
horizontal_def.description = S("Dispenser") horizontal_def.description = S("Dispenser")
horizontal_def._tt_help = S("9 inventory slots") .. "\n" .. S("Launches item when powered by redstone power") horizontal_def._tt_help = S("9 inventory slots") .. "\n" .. S("Launches item when powered by redstone power")
horizontal_def._doc_items_longdesc = S("A dispenser is a block which acts as a redstone component which, when powered with redstone power, dispenses an item. It has a container with 9 inventory slots.") horizontal_def._doc_items_longdesc = S("A dispenser is a block which acts as a redstone component which, when powered with redstone power, dispenses an item. It has a container with 9 inventory slots.")
horizontal_def._doc_items_usagehelp = S("Place the dispenser in one of 6 possible directions. The “hole” is where items will fly out of the dispenser. Use the dispenser to access its inventory. Insert the items you wish to dispense. Supply the dispenser with redstone energy once to dispense a random item.").."\n\n".. horizontal_def._doc_items_usagehelp = S("Place the dispenser in one of 6 possible directions. The “hole” is where items will fly out of the dispenser. Use the dispenser to access its inventory. Insert the items you wish to dispense. Supply the dispenser with redstone energy once to dispense a random item.")
.. "\n\n" ..
S("The dispenser will do different things, depending on the dispensed item:") .. "\n\n" .. S("The dispenser will do different things, depending on the dispensed item:") .. "\n\n" ..

View file

@ -9,23 +9,36 @@ are so many weird tables below.
]] ]]
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local C = minetest.colorize
local F = minetest.formspec_escape
-- For after_place_node local dropper_formspec = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[4.125,0.375;" .. F(C(mcl_formspec.label_color, S("Dropper"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(4.125, 0.75, 3, 3),
"list[context;main;4.125,0.75;3,3;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[context;main]",
"listring[current_player;main]",
})
---For after_place_node
---@param pos Vector
local function setup_dropper(pos) local function setup_dropper(pos)
-- Set formspec and inventory -- Set formspec and inventory
local form = "size[9,8.75]"..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,4.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
"list[current_player;main;0,7.74;9,1;]"..
mcl_formspec.get_itemslot_bg(0,7.74,9,1)..
"label[3,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Dropper"))).."]"..
"list[context;main;3,0.5;3,3;]"..
mcl_formspec.get_itemslot_bg(3,0.5,3,3)..
"listring[context;main]"..
"listring[current_player;main]"
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", form) meta:set_string("formspec", dropper_formspec)
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size("main", 9) inv:set_size("main", 9)
end end
@ -61,8 +74,7 @@ local dropperdef = {
for i = 1, inv:get_size("main") do for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i) local stack = inv:get_stack("main", i)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} minetest.add_item(vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5), stack)
minetest.add_item(p, stack)
end end
end end
meta:from_table(meta2) meta:from_table(meta2)
@ -106,9 +118,9 @@ local dropperdef = {
if node.name == "mcl_droppers:dropper" then if node.name == "mcl_droppers:dropper" then
droppos = vector.subtract(pos, minetest.facedir_to_dir(node.param2)) droppos = vector.subtract(pos, minetest.facedir_to_dir(node.param2))
elseif node.name == "mcl_droppers:dropper_up" then elseif node.name == "mcl_droppers:dropper_up" then
droppos = {x=pos.x, y=pos.y+1, z=pos.z} droppos = vector.offset(pos, 0, 1, 0)
elseif node.name == "mcl_droppers:dropper_down" then elseif node.name == "mcl_droppers:dropper_down" then
droppos = {x=pos.x, y=pos.y-1, z=pos.z} droppos = vector.offset(pos, 0, -1, 0)
end end
local dropnode = minetest.get_node(droppos) local dropnode = minetest.get_node(droppos)
-- Do not drop into solid nodes, unless they are containers -- Do not drop into solid nodes, unless they are containers
@ -136,11 +148,11 @@ local dropperdef = {
if not dropped and not dropnodedef.groups.container then if not dropped and not dropnodedef.groups.container then
-- Drop item normally -- Drop item normally
local pos_variation = 100 local pos_variation = 100
droppos = { droppos = vector.offset(droppos,
x = droppos.x + math.random(-pos_variation, pos_variation) / 1000, math.random(-pos_variation, pos_variation) / 1000,
y = droppos.y + math.random(-pos_variation, pos_variation) / 1000, math.random(-pos_variation, pos_variation) / 1000,
z = droppos.z + math.random(-pos_variation, pos_variation) / 1000, math.random(-pos_variation, pos_variation) / 1000
} )
local item_entity = minetest.add_item(droppos, dropitem) local item_entity = minetest.add_item(droppos, dropitem)
local drop_vel = vector.subtract(droppos, pos) local drop_vel = vector.subtract(droppos, pos)
local speed = 3 local speed = 3
@ -166,6 +178,7 @@ function horizontal_def.after_place_node(pos, placer, itemstack, pointed_thing)
setup_dropper(pos) setup_dropper(pos)
orientate_dropper(pos, placer) orientate_dropper(pos, placer)
end end
horizontal_def.tiles = { horizontal_def.tiles = {
"default_furnace_top.png", "default_furnace_bottom.png", "default_furnace_top.png", "default_furnace_bottom.png",
"default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png",

View file

@ -1,4 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
local MAX_NAME_LENGTH = 35 local MAX_NAME_LENGTH = 35
local MAX_WEAR = 65535 local MAX_WEAR = 65535
@ -10,35 +12,59 @@ local MATERIAL_TOOL_REPAIR_BOOST = {
MAX_WEAR, -- 100% MAX_WEAR, -- 100%
} }
---@param set_name? string
local function get_anvil_formspec(set_name) local function get_anvil_formspec(set_name)
if not set_name then if not set_name then
set_name = "" set_name = ""
end end
return "size[9,8.75]"..
"background[-0.19,-0.25;9.41,9.49;mcl_anvils_inventory.png]".. return table.concat({
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "formspec_version[4]",
"list[current_player;main;0,4.5;9,3;9]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
"list[current_player;main;0,7.74;9,1;]".. "label[4.125,0.375;" .. F(C(mcl_formspec.label_color, S("Repair and Name"))) .. "]",
mcl_formspec.get_itemslot_bg(0,7.74,9,1)..
"list[context;input;1,2.5;1,1;]".. "image[0.875,0.375;1.75,1.75;mcl_anvils_inventory_hammer.png]",
mcl_formspec.get_itemslot_bg(1,2.5,1,1)..
"list[context;input;4,2.5;1,1;1]".. "field[4.125,0.75;7.25,1;name;;" .. F(set_name) .. "]",
mcl_formspec.get_itemslot_bg(4,2.5,1,1).. "field_close_on_enter[name;false]",
"list[context;output;8,2.5;1,1;]".. "set_focus[name;true]",
mcl_formspec.get_itemslot_bg(8,2.5,1,1)..
"label[3,0.1;"..minetest.formspec_escape(minetest.colorize("#313131", S("Repair and Name"))).."]".. mcl_formspec.get_itemslot_bg_v4(1.625, 2.6, 1, 1),
"field[3.25,1;4,1;name;;"..minetest.formspec_escape(set_name).."]".. "list[context;input;1.625,2.6;1,1;]",
"field_close_on_enter[name;false]"..
"button[7,0.7;2,1;name_button;"..minetest.formspec_escape(S("Set Name")).."]".. "image[3.5,2.6;1,1;mcl_anvils_inventory_cross.png]",
"listring[context;output]"..
"listring[current_player;main]".. mcl_formspec.get_itemslot_bg_v4(5.375, 2.6, 1, 1),
"listring[context;input]".. "list[context;input;5.375,2.6;1,1;1]",
"listring[current_player;main]"
"image[6.75,2.6;2,1;mcl_anvils_inventory_arrow.png]",
mcl_formspec.get_itemslot_bg_v4(9.125, 2.6, 1, 1),
"list[context;output;9.125,2.6;1,1;]",
-- Player Inventory
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
-- Listrings
"listring[context;output]",
"listring[current_player;main]",
"listring[context;input]",
"listring[current_player;main]",
})
end end
-- Given a tool and material stack, returns how many items of the material stack -- Given a tool and material stack, returns how many items of the material stack
-- needs to be used up to repair the tool. -- needs to be used up to repair the tool.
---@param tool ItemStack
---@param material ItemStack
---@return integer
local function get_consumed_materials(tool, material) local function get_consumed_materials(tool, material)
local wear = tool:get_wear() local wear = tool:get_wear()
--local health = (MAX_WEAR - wear) --local health = (MAX_WEAR - wear)
@ -53,27 +79,20 @@ local function get_consumed_materials(tool, material)
return materials_used return materials_used
end end
local function contains(table, value)
for _, i in pairs(table) do
if i == value then
return true
end
end
return false
end
-- Given 2 input stacks, tells you which is the tool and which is the material. -- Given 2 input stacks, tells you which is the tool and which is the material.
-- Returns ("tool", input1, input2) if input1 is tool and input2 is material. -- Returns ("tool", input1, input2) if input1 is tool and input2 is material.
-- Returns ("material", input2, input1) if input1 is material and input2 is tool. -- Returns ("material", input2, input1) if input1 is material and input2 is tool.
-- Returns nil otherwise. -- Returns nil otherwise.
---@param input1 ItemStack
---@param input2 ItemStack
local function distinguish_tool_and_material(input1, input2) local function distinguish_tool_and_material(input1, input2)
local def1 = input1:get_definition() local def1 = input1:get_definition()
local def2 = input2:get_definition() local def2 = input2:get_definition()
local r1 = def1._repair_material local r1 = def1._repair_material
local r2 = def2._repair_material local r2 = def2._repair_material
if def1.type == "tool" and r1 and type(r1) == "table" and contains(r1, input2) then if def1.type == "tool" and r1 and type(r1) == "table" and table.indexof(r1, input2) ~= -1 then
return "tool", input1, input2 return "tool", input1, input2
elseif def2.type == "tool" and r2 and type(r2) == "table" and contains(r2, input1) then elseif def2.type == "tool" and r2 and type(r2) == "table" and table.indexof(r1, input1) ~= -1 then
return "material", input2, input1 return "material", input2, input1
elseif def1.type == "tool" and r1 then elseif def1.type == "tool" and r1 then
return "tool", input1, input2 return "tool", input1, input2
@ -84,7 +103,8 @@ local function distinguish_tool_and_material(input1, input2)
end end
end end
-- Helper function to make sure update_anvil_slots NEVER overstacks the output slot ---Helper function to make sure update_anvil_slots NEVER overstacks the output slot
---@param stack ItemStack
local function fix_stack_size(stack) local function fix_stack_size(stack)
if not stack or stack == "" then return "" end if not stack or stack == "" then return "" end
local count = stack:get_count() local count = stack:get_count()
@ -99,6 +119,7 @@ end
-- Update the inventory slots of an anvil node. -- Update the inventory slots of an anvil node.
-- meta: Metadata of anvil node -- meta: Metadata of anvil node
---@param meta NodeMetaRef
local function update_anvil_slots(meta) local function update_anvil_slots(meta)
local inv = meta:get_inventory() local inv = meta:get_inventory()
local new_name = meta:get_string("set_name") local new_name = meta:get_string("set_name")
@ -159,7 +180,7 @@ local function update_anvil_slots(meta)
has_correct_material = true has_correct_material = true
end end
else else
if contains(repair, material_name) then if table.indexof(repair, material_name) ~= -1 then
has_correct_material = true has_correct_material = true
else else
for _, r in pairs(repair) do for _, r in pairs(repair) do
@ -231,28 +252,32 @@ local function update_anvil_slots(meta)
end end
end end
-- Drop input items of anvil at pos with metadata meta ---Drop input items of anvil at pos with metadata meta
---@param pos Vector
---@param meta NodeMetaRef
local function drop_anvil_items(pos, meta) local function drop_anvil_items(pos, meta)
local inv = meta:get_inventory() local inv = meta:get_inventory()
for i = 1, inv:get_size("input") do for i = 1, inv:get_size("input") do
local stack = inv:get_stack("input", i) local stack = inv:get_stack("input", i)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} local p = vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5)
minetest.add_item(p, stack) minetest.add_item(p, stack)
end end
end end
end end
---@param pos Vector
---@param node node
local function damage_particles(pos, node) local function damage_particles(pos, node)
minetest.add_particlespawner({ minetest.add_particlespawner({
amount = 30, amount = 30,
time = 0.1, time = 0.1,
minpos = vector.add(pos, {x=-0.5, y=-0.5, z=-0.5}), minpos = vector.offset(pos, -0.5, -0.5, -0.5),
maxpos = vector.add(pos, {x=0.5, y=-0.25, z=0.5}), maxpos = vector.offset(pos, 0.5, -0.25, 0.5),
minvel = {x=-0.5, y=0.05, z=-0.5}, minvel = vector.new(-0.5, 0.05, -0.5),
maxvel = {x=0.5, y=0.3, z=0.5}, maxvel = vector.new(0.5, 0.3, 0.5),
minacc = {x=0, y=-9.81, z=0}, minacc = vector.new(0, -9.81, 0),
maxacc = {x=0, y=-9.81, z=0}, maxacc = vector.new(0, -9.81, 0),
minexptime = 0.1, minexptime = 0.1,
maxexptime = 0.5, maxexptime = 0.5,
minsize = 0.4, minsize = 0.4,
@ -267,12 +292,12 @@ local function destroy_particles(pos, node)
minetest.add_particlespawner({ minetest.add_particlespawner({
amount = math.random(20, 30), amount = math.random(20, 30),
time = 0.1, time = 0.1,
minpos = vector.add(pos, {x=-0.4, y=-0.4, z=-0.4}), minpos = vector.offset(pos, -0.4, -0.4, -0.4),
maxpos = vector.add(pos, {x=0.4, y=0.4, z=0.4}), maxpos = vector.offset(pos, 0.4, 0.4, 0.4),
minvel = {x=-0.5, y=-0.1, z=-0.5}, minvel = vector.new(-0.5, -0.1, -0.5),
maxvel = {x=0.5, y=0.2, z=0.5}, maxvel = vector.new(0.5, 0.2, 0.5),
minacc = {x=0, y=-9.81, z=0}, minacc = vector.new(0, -9.81, 0),
maxacc = {x=0, y=-9.81, z=0}, maxacc = vector.new(0, -9.81, 0),
minexptime = 0.2, minexptime = 0.2,
maxexptime = 0.65, maxexptime = 0.65,
minsize = 0.8, minsize = 0.8,
@ -305,12 +330,13 @@ local function damage_anvil(pos)
minetest.sound_play(mcl_sounds.node_sound_metal_defaults().dug, { pos = pos, max_hear_distance = 16 }, true) minetest.sound_play(mcl_sounds.node_sound_metal_defaults().dug, { pos = pos, max_hear_distance = 16 }, true)
minetest.remove_node(pos) minetest.remove_node(pos)
destroy_particles(pos, node) destroy_particles(pos, node)
minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z}) minetest.check_single_for_falling(vector.offset(pos, 0, 1, 0))
return true return true
end end
end end
-- Roll a virtual dice and damage anvil at a low chance. ---Roll a virtual dice and damage anvil at a low chance.
---@param pos Vector
local function damage_anvil_by_using(pos) local function damage_anvil_by_using(pos)
local r = math.random(1, 100) local r = math.random(1, 100)
-- 12% chance -- 12% chance
@ -321,6 +347,8 @@ local function damage_anvil_by_using(pos)
end end
end end
---@param pos Vector
---@param distance number
local function damage_anvil_by_falling(pos, distance) local function damage_anvil_by_falling(pos, distance)
local r = math.random(1, 100) local r = math.random(1, 100)
if distance > 1 then if distance > 1 then
@ -330,16 +358,19 @@ local function damage_anvil_by_falling(pos, distance)
end end
end end
---@type nodebox
local anvilbox = { local anvilbox = {
type = "fixed", type = "fixed",
fixed = { fixed = {
{ -8 / 16, -8 / 16, -6 / 16, 8 / 16, 8 / 16, 6 / 16 }, { -8 / 16, -8 / 16, -6 / 16, 8 / 16, 8 / 16, 6 / 16 },
}, },
} }
---@type node_definition
local anvildef = { local anvildef = {
groups = { pickaxey = 1, falling_node = 1, falling_node_damage = 1, crush_after_fall = 1, deco_block = 1, anvil = 1 }, groups = { pickaxey = 1, falling_node = 1, falling_node_damage = 1, crush_after_fall = 1, deco_block = 1, anvil = 1 },
tiles = { "mcl_anvils_anvil_top_damaged_0.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png" }, tiles = { "mcl_anvils_anvil_top_damaged_0.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png" },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, use_texture_alpha = "opaque",
_tt_help = S("Repair and rename items"), _tt_help = S("Repair and rename items"),
paramtype = "light", paramtype = "light",
sunlight_propagates = true, sunlight_propagates = true,
@ -353,7 +384,7 @@ local anvildef = {
{ -5 / 16, -4 / 16, -4 / 16, 5 / 16, -3 / 16, 4 / 16 }, { -5 / 16, -4 / 16, -4 / 16, 5 / 16, -3 / 16, 4 / 16 },
{ -4 / 16, -3 / 16, -2 / 16, 4 / 16, 2 / 16, 2 / 16 }, { -4 / 16, -3 / 16, -2 / 16, 4 / 16, 2 / 16, 2 / 16 },
{ -8 / 16, 2 / 16, -5 / 16, 8 / 16, 8 / 16, 5 / 16 }, { -8 / 16, 2 / 16, -5 / 16, 8 / 16, 8 / 16, 5 / 16 },
} },
}, },
selection_box = anvilbox, selection_box = anvilbox,
collision_box = anvilbox, collision_box = anvilbox,
@ -504,22 +535,20 @@ local anvildef = {
minetest.record_protection_violation(pos, sender_name) minetest.record_protection_violation(pos, sender_name)
return return
end end
if fields.name_button or fields.name then
local set_name if fields.name then
if fields.name == nil then
set_name = ""
else
set_name = fields.name
end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
-- Limit name length -- Limit name length
set_name = string.sub(set_name, 1, MAX_NAME_LENGTH) local set_name = string.sub(fields.name, 1, MAX_NAME_LENGTH)
meta:set_string("set_name", set_name) meta:set_string("set_name", set_name)
update_anvil_slots(meta) update_anvil_slots(meta)
meta:set_string("formspec", get_anvil_formspec(set_name)) meta:set_string("formspec", get_anvil_formspec(set_name))
end end
end, end,
} }
if minetest.get_modpath("screwdriver") then if minetest.get_modpath("screwdriver") then
anvildef.on_rotate = screwdriver.rotate_simple anvildef.on_rotate = screwdriver.rotate_simple
end end
@ -530,10 +559,13 @@ anvildef0._doc_items_longdesc =
S("The anvil allows you to repair tools and armor, and to give names to items. It has a limited durability, however. Don't let it fall on your head, it could be quite painful!") S("The anvil allows you to repair tools and armor, and to give names to items. It has a limited durability, however. Don't let it fall on your head, it could be quite painful!")
anvildef0._doc_items_usagehelp = anvildef0._doc_items_usagehelp =
S("To use an anvil, rightclick it. An anvil has 2 input slots (on the left) and one output slot.") .. "\n" .. S("To use an anvil, rightclick it. An anvil has 2 input slots (on the left) and one output slot.") .. "\n" ..
S("To rename items, put an item stack in one of the item slots while keeping the other input slot empty. Type in a name, hit enter or “Set Name”, then take the renamed item from the output slot.").."\n".. S("To rename items, put an item stack in one of the item slots while keeping the other input slot empty. Type in a name, hit enter or “Set Name”, then take the renamed item from the output slot.")
.. "\n" ..
S("There are two possibilities to repair tools (and armor):") .. "\n" .. S("There are two possibilities to repair tools (and armor):") .. "\n" ..
S("• Tool + Tool: Place two tools of the same type in the input slots. The “health” of the repaired tool is the sum of the “health” of both input tools, plus a 12% bonus.").."\n".. S("• Tool + Tool: Place two tools of the same type in the input slots. The “health” of the repaired tool is the sum of the “health” of both input tools, plus a 12% bonus.")
S("• Tool + Material: Some tools can also be repaired by combining them with an item that it's made of. For example, iron pickaxes can be repaired with iron ingots. This repairs the tool by 25%.").."\n".. .. "\n" ..
S("• Tool + Material: Some tools can also be repaired by combining them with an item that it's made of. For example, iron pickaxes can be repaired with iron ingots. This repairs the tool by 25%.")
.. "\n" ..
S("Armor counts as a tool. It is possible to repair and rename a tool in a single step.") .. "\n\n" .. S("Armor counts as a tool. It is possible to repair and rename a tool in a single step.") .. "\n\n" ..
S("The anvil has limited durability and 3 damage levels: undamaged, slightly damaged and very damaged. Each time you repair or rename something, there is a 12% chance the anvil gets damaged. Anvils also have a chance of being damaged when they fall by more than 1 block. If a very damaged anvil is damaged again, it is destroyed.") S("The anvil has limited durability and 3 damage levels: undamaged, slightly damaged and very damaged. Each time you repair or rename something, there is a 12% chance the anvil gets damaged. Anvils also have a chance of being damaged when they fall by more than 1 block. If a very damaged anvil is damaged again, it is destroyed.")
@ -542,14 +574,16 @@ anvildef1.description = S("Slightly Damaged Anvil")
anvildef1._doc_items_create_entry = false anvildef1._doc_items_create_entry = false
anvildef1.groups.anvil = 2 anvildef1.groups.anvil = 2
anvildef1._doc_items_create_entry = false anvildef1._doc_items_create_entry = false
anvildef1.tiles = {"mcl_anvils_anvil_top_damaged_1.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png"} anvildef1.tiles = { "mcl_anvils_anvil_top_damaged_1.png^[transformR90", "mcl_anvils_anvil_base.png",
"mcl_anvils_anvil_side.png" }
local anvildef2 = table.copy(anvildef) local anvildef2 = table.copy(anvildef)
anvildef2.description = S("Very Damaged Anvil") anvildef2.description = S("Very Damaged Anvil")
anvildef2._doc_items_create_entry = false anvildef2._doc_items_create_entry = false
anvildef2.groups.anvil = 3 anvildef2.groups.anvil = 3
anvildef2._doc_items_create_entry = false anvildef2._doc_items_create_entry = false
anvildef2.tiles = {"mcl_anvils_anvil_top_damaged_2.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png"} anvildef2.tiles = { "mcl_anvils_anvil_top_damaged_2.png^[transformR90", "mcl_anvils_anvil_base.png",
"mcl_anvils_anvil_side.png" }
minetest.register_node("mcl_anvils:anvil", anvildef0) minetest.register_node("mcl_anvils:anvil", anvildef0)
minetest.register_node("mcl_anvils:anvil_damage_1", anvildef1) minetest.register_node("mcl_anvils:anvil_damage_1", anvildef1)
@ -562,7 +596,7 @@ if minetest.get_modpath("mcl_core") then
{ "mcl_core:ironblock", "mcl_core:ironblock", "mcl_core:ironblock" }, { "mcl_core:ironblock", "mcl_core:ironblock", "mcl_core:ironblock" },
{ "", "mcl_core:iron_ingot", "" }, { "", "mcl_core:iron_ingot", "" },
{ "mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot" }, { "mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot" },
} },
}) })
end end

View file

@ -8,6 +8,7 @@ local open_barrels = {}
local drop_content = mcl_util.drop_items_from_meta_container("main") local drop_content = mcl_util.drop_items_from_meta_container("main")
---@param pos Vector
local function on_blast(pos) local function on_blast(pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
drop_content(pos, node) drop_content(pos, node)
@ -47,15 +48,18 @@ local function barrel_open(pos, node, clicker)
minetest.show_formspec(playername, minetest.show_formspec(playername,
"mcl_barrels:barrel_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z, "mcl_barrels:barrel_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z,
table.concat({ table.concat({
"size[9,8.75]", "formspec_version[4]",
"label[0,0;"..F(C("#313131", name)).."]", "size[11.75,10.425]",
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]",
mcl_formspec.get_itemslot_bg(0, 0.5, 9, 3), "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
"label[0,4.0;"..F(C("#313131", S("Inventory"))).."]", mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"list[current_player;main;0,4.5;9,3;9]", "list[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main;0.375,0.75;9,3;]",
mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3), "label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
"list[current_player;main;0,7.74;9,1;]", mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1), "list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main]", "listring[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main]",
"listring[current_player;main]", "listring[current_player;main]",
}) })
@ -66,6 +70,7 @@ local function barrel_open(pos, node, clicker)
minetest.sound_play({ name = "mcl_barrels_default_barrel_open", pos = pos, gain = 0.5, max_hear_distance = 16 }, true) minetest.sound_play({ name = "mcl_barrels_default_barrel_open", pos = pos, gain = 0.5, max_hear_distance = 16 }, true)
end end
---@param pos Vector
local function close_forms(pos) local function close_forms(pos)
local players = minetest.get_connected_players() local players = minetest.get_connected_players()
local formname = "mcl_barrels:barrel_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z local formname = "mcl_barrels:barrel_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z
@ -76,15 +81,18 @@ local function close_forms(pos)
end end
end end
---@param pos Vector
local function update_after_close(pos) local function update_after_close(pos)
local node = minetest.get_node_or_nil(pos) local node = minetest.get_node_or_nil(pos)
if not node then return end if not node then return end
if node.name == "mcl_barrels:barrel_open" then if node.name == "mcl_barrels:barrel_open" then
minetest.swap_node(pos, { name = "mcl_barrels:barrel_closed", param2 = node.param2 }) minetest.swap_node(pos, { name = "mcl_barrels:barrel_closed", param2 = node.param2 })
minetest.sound_play({name="mcl_barrels_default_barrel_close", pos=pos, gain=0.5, max_hear_distance=16}, true) minetest.sound_play({ name = "mcl_barrels_default_barrel_close", pos = pos, gain = 0.5, max_hear_distance = 16 },
true)
end end
end end
---@param player ObjectRef
local function close_barrel(player) local function close_barrel(player)
local name = player:get_player_name() local name = player:get_player_name()
local open = open_barrels[name] local open = open_barrels[name]
@ -106,7 +114,9 @@ minetest.register_node("mcl_barrels:barrel_closed", {
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
on_place = function(itemstack, placer, pointed_thing) on_place = function(itemstack, placer, pointed_thing)
minetest.rotate_and_place(itemstack, placer, pointed_thing, minetest.is_creative_enabled(placer:get_player_name()), {}, false) minetest.rotate_and_place(itemstack, placer, pointed_thing,
minetest.is_creative_enabled(placer:get_player_name()), {}
, false)
return itemstack return itemstack
end, end,
stack_max = 64, stack_max = 64,
@ -155,7 +165,15 @@ minetest.register_node("mcl_barrels:barrel_open", {
drop = "mcl_barrels:barrel_closed", drop = "mcl_barrels:barrel_closed",
stack_max = 64, stack_max = 64,
sounds = mcl_sounds.node_sound_wood_defaults(), sounds = mcl_sounds.node_sound_wood_defaults(),
groups = {handy = 1, axey = 1, container = 2, material_wood = 1, flammable = -1, deco_block = 1, not_in_creative_inventory = 1}, groups = {
handy = 1,
axey = 1,
container = 2,
material_wood = 1,
flammable = -1,
deco_block = 1,
not_in_creative_inventory = 1
},
allow_metadata_inventory_move = protection_check_move, allow_metadata_inventory_move = protection_check_move,
allow_metadata_inventory_take = protection_check_put_take, allow_metadata_inventory_take = protection_check_put_take,
allow_metadata_inventory_put = protection_check_put_take, allow_metadata_inventory_put = protection_check_put_take,
@ -196,7 +214,7 @@ minetest.register_craft({
{ "group:wood", "group:wood_slab", "group:wood" }, { "group:wood", "group:wood_slab", "group:wood" },
{ "group:wood", "", "group:wood" }, { "group:wood", "", "group:wood" },
{ "group:wood", "group:wood_slab", "group:wood" }, { "group:wood", "group:wood_slab", "group:wood" },
} },
}) })
minetest.register_craft({ minetest.register_craft({

View file

@ -1,5 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local C = minetest.colorize
local F = minetest.formspec_escape
local LIGHT_ACTIVE_FURNACE = 13 local LIGHT_ACTIVE_FURNACE = 13
@ -8,60 +9,82 @@ local LIGHT_ACTIVE_FURNACE = 13
-- --
local function active_formspec(fuel_percent, item_percent) local function active_formspec(fuel_percent, item_percent)
return "size[9,8.75]".. return table.concat({
"label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "formspec_version[4]",
"list[current_player;main;0,4.5;9,3;9]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Blast Furnace"))) .. "]",
"list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. "list[context;src;3.5,0.75;1,1;]",
"label[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Blast Furnace"))).."]"..
"list[context;src;2.75,0.5;1,1;]".. "image[3.5,2;1,1;default_furnace_fire_bg.png^[lowpart:" ..
mcl_formspec.get_itemslot_bg(2.75,0.5,1,1).. (100 - fuel_percent) .. ":default_furnace_fire_fg.png]",
"list[context;fuel;2.75,2.5;1,1;]"..
mcl_formspec.get_itemslot_bg(2.75,2.5,1,1).. mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;dst;5.75,1.5;1,1;]".. "list[context;fuel;3.5,3.25;1,1;]",
mcl_formspec.get_itemslot_bg(5.75,1.5,1,1)..
"image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:".. "image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[lowpart:" ..
(100-fuel_percent)..":default_furnace_fire_fg.png]".. (item_percent) .. ":gui_furnace_arrow_fg.png^[transformR270]",
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[lowpart:".. mcl_formspec.get_itemslot_bg_v4(7.875, 2, 1, 1, 0.2),
(item_percent)..":gui_furnace_arrow_fg.png^[transformR270]".. "list[context;dst;7.875,2;1,1;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
-- Craft guide button temporarily removed due to Minetest bug. -- Craft guide button temporarily removed due to Minetest bug.
-- TODO: Add it back when the Minetest bug is fixed. -- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]".. --"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]".. --"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]".. "listring[context;dst]",
"listring[context;src]".. "listring[current_player;main]",
"listring[current_player;main]".. "listring[context;src]",
"listring[context;fuel]".. "listring[current_player;main]",
"listring[current_player;main]" "listring[context;fuel]",
"listring[current_player;main]",
})
end end
local inactive_formspec = "size[9,8.75]".. local inactive_formspec = table.concat({
"label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "formspec_version[4]",
"list[current_player;main;0,4.5;9,3;9]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Blast Furnace"))) .. "]",
"list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. "list[context;src;3.5,0.75;1,1;]",
"label[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Blast Furnace"))).."]"..
"list[context;src;2.75,0.5;1,1;]".. "image[3.5,2;1,1;default_furnace_fire_bg.png]",
mcl_formspec.get_itemslot_bg(2.75,0.5,1,1)..
"list[context;fuel;2.75,2.5;1,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
mcl_formspec.get_itemslot_bg(2.75,2.5,1,1).. "list[context;fuel;3.5,3.25;1,1;]",
"list[context;dst;5.75,1.5;1,1;]"..
mcl_formspec.get_itemslot_bg(5.75,1.5,1,1).. "image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[transformR270]",
"image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[transformR270]".. mcl_formspec.get_itemslot_bg_v4(7.875, 2, 1, 1, 0.2),
"list[context;dst;7.875,2;1,1;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
-- Craft guide button temporarily removed due to Minetest bug. -- Craft guide button temporarily removed due to Minetest bug.
-- TODO: Add it back when the Minetest bug is fixed. -- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]".. --"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]".. --"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]".. "listring[context;dst]",
"listring[context;src]".. "listring[current_player;main]",
"listring[current_player;main]".. "listring[context;src]",
"listring[context;fuel]".. "listring[current_player;main]",
"listring[current_player;main]" "listring[context;fuel]",
"listring[current_player;main]",
})
local receive_fields = function(pos, formname, fields, sender) local receive_fields = function(pos, formname, fields, sender)
if fields.craftguide then if fields.craftguide then
@ -160,17 +183,17 @@ local function spawn_flames(pos, param2)
local minrelpos, maxrelpos local minrelpos, maxrelpos
local dir = minetest.facedir_to_dir(param2) local dir = minetest.facedir_to_dir(param2)
if dir.x > 0 then if dir.x > 0 then
minrelpos = { x = -0.6, y = -0.05, z = -0.25 } minrelpos = vector.new(-0.6, -0.05, -0.25)
maxrelpos = { x = -0.55, y = -0.45, z = 0.25 } maxrelpos = vector.new(-0.55, -0.45, 0.25)
elseif dir.x < 0 then elseif dir.x < 0 then
minrelpos = { x = 0.55, y = -0.05, z = -0.25 } minrelpos = vector.new(0.55, -0.05, -0.25)
maxrelpos = { x = 0.6, y = -0.45, z = 0.25 } maxrelpos = vector.new(0.6, -0.45, 0.25)
elseif dir.z > 0 then elseif dir.z > 0 then
minrelpos = { x = -0.25, y = -0.05, z = -0.6 } minrelpos = vector.new(-0.25, -0.05, -0.6)
maxrelpos = { x = 0.25, y = -0.45, z = -0.55 } maxrelpos = vector.new(0.25, 0.45, -0.55)
elseif dir.z < 0 then elseif dir.z < 0 then
minrelpos = { x = -0.25, y = -0.05, z = 0.55 } minrelpos = vector.new(-0.25, -0.05, 0.55)
maxrelpos = { x = 0.25, y = -0.45, z = 0.6 } maxrelpos = vector.new(0.25, -0.45, 0.6)
else else
return return
end end
@ -179,8 +202,8 @@ local function spawn_flames(pos, param2)
time = 0, time = 0,
minpos = vector.add(pos, minrelpos), minpos = vector.add(pos, minrelpos),
maxpos = vector.add(pos, maxrelpos), maxpos = vector.add(pos, maxrelpos),
minvel = { x = -0.01, y = 0, z = -0.01 }, minvel = vector.new(-0.01, 0, -0.01),
maxvel = { x = 0.01, y = 0.1, z = 0.01 }, maxvel = vector.new(0.01, 0.1, 0.01),
minexptime = 0.3, minexptime = 0.3,
maxexptime = 0.6, maxexptime = 0.6,
minsize = 0.4, minsize = 0.4,
@ -415,7 +438,8 @@ end
minetest.register_node("mcl_blast_furnace:blast_furnace", { minetest.register_node("mcl_blast_furnace:blast_furnace", {
description = S("Blast Furnace"), description = S("Blast Furnace"),
_tt_help = S("Smelts ores faster than furnace"), _tt_help = S("Smelts ores faster than furnace"),
_doc_items_longdesc = S("Blast Furnaces smelt several items, mainly ores and armor, using a furnace fuel, but twice as fast as a normal furnace."), _doc_items_longdesc = S(
"Blast Furnaces smelt several items, mainly ores and armor, using a furnace fuel, but twice as fast as a normal furnace."),
_doc_items_usagehelp = _doc_items_usagehelp =
S("Use the blast furnace to open the furnace menu.") .. "\n" .. S("Use the blast furnace to open the furnace menu.") .. "\n" ..
S("Place a furnace fuel in the lower slot and the source material in the upper slot.") .. "\n" .. S("Place a furnace fuel in the lower slot and the source material in the upper slot.") .. "\n" ..
@ -442,8 +466,7 @@ minetest.register_node("mcl_blast_furnace:blast_furnace", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1) local stack = inv:get_stack(listname, 1)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} minetest.add_item(vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5), stack)
minetest.add_item(p, stack)
end end
end end
meta:from_table(meta2) meta:from_table(meta2)
@ -499,8 +522,10 @@ minetest.register_node("mcl_blast_furnace:blast_furnace_active", {
tiles = { tiles = {
"blast_furnace_top.png", "blast_furnace_top.png", "blast_furnace_top.png", "blast_furnace_top.png",
"blast_furnace_side.png", "blast_furnace_side.png", "blast_furnace_side.png", "blast_furnace_side.png",
"blast_furnace_side.png", {name = "blast_furnace_front_on.png", "blast_furnace_side.png", {
animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 48}}, name = "blast_furnace_front_on.png",
animation = { type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 48 }
},
}, },
paramtype2 = "facedir", paramtype2 = "facedir",
paramtype = "light", paramtype = "light",
@ -519,7 +544,11 @@ minetest.register_node("mcl_blast_furnace:blast_furnace_active", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1) local stack = inv:get_stack(listname, 1)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} local p = vector.new(
pos.x + math.random(0, 10) / 10 - 0.5,
pos.y,
pos.z + math.random(0, 10) / 10 - 0.5
)
minetest.add_item(p, stack) minetest.add_item(p, stack)
end end
end end
@ -570,4 +599,3 @@ minetest.register_lbm({
spawn_flames(pos, node.param2) spawn_flames(pos, node.param2)
end, end,
}) })

View file

@ -85,7 +85,8 @@ local function write(itemstack, user, pointed_thing)
local node = minetest.get_node(pointed_thing.under) local node = minetest.get_node(pointed_thing.under)
if user and not user:get_player_control().sneak then if user and not user:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or
itemstack
end end
end end
end end
@ -106,7 +107,8 @@ local function read(itemstack, user, pointed_thing)
local node = minetest.get_node(pointed_thing.under) local node = minetest.get_node(pointed_thing.under)
if user and not user:get_player_control().sneak then if user and not user:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or
itemstack
end end
end end
end end
@ -125,7 +127,9 @@ minetest.register_craftitem("mcl_books:writable_book", {
description = S("Book and Quill"), description = S("Book and Quill"),
_tt_help = S("Write down some notes"), _tt_help = S("Write down some notes"),
_doc_items_longdesc = S("This item can be used to write down some notes."), _doc_items_longdesc = S("This item can be used to write down some notes."),
_doc_items_usagehelp = S("Hold it in the hand, then rightclick to read the current notes and edit then. You can edit the text as often as you like. You can also sign the book which turns it into a written book which you can stack, but it can't be edited anymore.").."\n".. _doc_items_usagehelp = S(
"Hold it in the hand, then rightclick to read the current notes and edit then. You can edit the text as often as you like. You can also sign the book which turns it into a written book which you can stack, but it can't be edited anymore.")
.. "\n" ..
S("A book can hold up to 4500 characters. The title length is limited to 64 characters."), S("A book can hold up to 4500 characters. The title length is limited to 64 characters."),
inventory_image = "mcl_books_book_writable.png", inventory_image = "mcl_books_book_writable.png",
groups = { book = 1 }, groups = { book = 1 },
@ -151,10 +155,13 @@ minetest.register_on_player_receive_fields(function ( player, formname, fields )
local formspec = "size[8,9]" .. local formspec = "size[8,9]" ..
header .. header ..
"background[-0.5,-0.5;9,10;mcl_books_book_bg.png]" .. "background[-0.5,-0.5;9,10;mcl_books_book_bg.png]" ..
"field[0.75,1;7.25,1;title;"..minetest.formspec_escape(minetest.colorize("#000000", S("Enter book title:")))..";]".. "field[0.75,1;7.25,1;title;" ..
"label[0.75,1.5;"..minetest.formspec_escape(minetest.colorize("#404040", S("by @1", name))).."]".. minetest.formspec_escape(minetest.colorize("#000000", S("Enter book title:"))) .. ";]" ..
"label[0.75,1.5;" ..
minetest.formspec_escape(minetest.colorize("#404040", S("by @1", name))) .. "]" ..
"button_exit[0.75,7.95;3,1;sign;" .. minetest.formspec_escape(S("Sign and Close")) .. "]" .. "button_exit[0.75,7.95;3,1;sign;" .. minetest.formspec_escape(S("Sign and Close")) .. "]" ..
"tooltip[sign;"..minetest.formspec_escape(S("Note: The book will no longer be editable after signing")).."]".. "tooltip[sign;" ..
minetest.formspec_escape(S("Note: The book will no longer be editable after signing")) .. "]" ..
"button[4.25,7.95;3,1;cancel;" .. minetest.formspec_escape(S("Cancel")) .. "]" "button[4.25,7.95;3,1;cancel;" .. minetest.formspec_escape(S("Cancel")) .. "]"
minetest.show_formspec(player:get_player_name(), "mcl_books:signing", formspec) minetest.show_formspec(player:get_player_name(), "mcl_books:signing", formspec)
end end
@ -202,10 +209,14 @@ end
-- Written Book -- Written Book
minetest.register_craftitem("mcl_books:written_book", { minetest.register_craftitem("mcl_books:written_book", {
description = S("Written Book"), description = S("Written Book"),
_doc_items_longdesc = S("Written books contain some text written by someone. They can be read and copied, but not edited."), _doc_items_longdesc = S(
_doc_items_usagehelp = S("Hold it in your hand, then rightclick to read the book.").."\n\n".. "Written books contain some text written by someone. They can be read and copied, but not edited."
),
S("To copy the text of the written book, place it into the crafting grid together with a book and quill (or multiple of those) and craft. The written book will not be consumed. Copies of copies can not be copied."), _doc_items_usagehelp = S("Hold it in your hand, then rightclick to read the book.") ..
"\n\n" ..
S(
"To copy the text of the written book, place it into the crafting grid together with a book and quill (or multiple of those) and craft. The written book will not be consumed. Copies of copies can not be copied."
),
inventory_image = "mcl_books_book_written.png", inventory_image = "mcl_books_book_written.png",
groups = { not_in_creative_inventory = 1, book = 1, no_rename = 1 }, groups = { not_in_creative_inventory = 1, book = 1, no_rename = 1 },
stack_max = 16, stack_max = 16,
@ -367,6 +378,9 @@ local function protection_check_put_take(pos, listname, index, stack, player)
end end
end end
---@param pos Vector
---@param node node
---@param clicker ObjectRef
local function bookshelf_gui(pos, node, clicker) local function bookshelf_gui(pos, node, clicker)
if not bookshelf_inv then return end if not bookshelf_inv then return end
local name = minetest.get_meta(pos):get_string("name") local name = minetest.get_meta(pos):get_string("name")
@ -380,15 +394,19 @@ local function bookshelf_gui(pos, node, clicker)
minetest.show_formspec(playername, minetest.show_formspec(playername,
"mcl_books:bookshelf_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z, "mcl_books:bookshelf_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z,
table.concat({ table.concat({
"size[9,8.75]", "formspec_version[4]",
"label[0,0;"..F(C("#313131", name)).."]", "size[11.75,10.425]",
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]",
mcl_formspec.get_itemslot_bg(0, 0.5, 9, 3), "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
"label[0,4.0;"..F(C("#313131", S("Inventory"))).."]", mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"list[current_player;main;0,4.5;9,3;9]", mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3, 0, "mcl_book_book_empty_slot.png"),
mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3), "list[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main;0.375,0.75;9,3;]",
"list[current_player;main;0,7.74;9,1;]", "label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1), mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main]", "listring[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main]",
"listring[current_player;main]", "listring[current_player;main]",
}) })
@ -413,8 +431,14 @@ minetest.register_node("mcl_books:bookshelf", {
stack_max = 64, stack_max = 64,
is_ground_content = false, is_ground_content = false,
groups = { groups = {
handy=1, axey=1, deco_block=1, material_wood=1, handy = 1,
flammable=3, fire_encouragement=30, fire_flammability=20, container=1 axey = 1,
deco_block = 1,
material_wood = 1,
flammable = 3,
fire_encouragement = 30,
fire_flammability = 20,
container = 1
}, },
drop = "mcl_books:book 3", drop = "mcl_books:book 3",
sounds = wood_sound, sounds = wood_sound,
@ -464,4 +488,3 @@ minetest.register_craft({
recipe = "mcl_books:bookshelf", recipe = "mcl_books:bookshelf",
burntime = 15, burntime = 15,
}) })

View file

@ -1,4 +1,13 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
local string = string
local table = table
local math = math
local sf = string.format
local mod_doc = minetest.get_modpath("doc") local mod_doc = minetest.get_modpath("doc")
-- Christmas chest setup -- Christmas chest setup
@ -50,7 +59,7 @@ local entity_animations = {
speed = 25, speed = 25,
open = { x = 0, y = 7 }, open = { x = 0, y = 7 },
close = { x = 13, y = 20 }, close = { x = 13, y = 20 },
} },
} }
minetest.register_entity("mcl_chests:chest", { minetest.register_entity("mcl_chests:chest", {
@ -72,7 +81,8 @@ minetest.register_entity("mcl_chests:chest", {
self.players[playername] = true self.players[playername] = true
if not self.is_open then if not self.is_open then
self:set_animation("open") self:set_animation("open")
minetest.sound_play(self.sound_prefix .. "_open", {pos=self.node_pos, gain=0.5, max_hear_distance = 16}, true) minetest.sound_play(self.sound_prefix .. "_open", { pos = self.node_pos, gain = 0.5, max_hear_distance = 16 },
true)
self.is_open = true self.is_open = true
end end
end, end,
@ -85,7 +95,9 @@ minetest.register_entity("mcl_chests:chest", {
return return
end end
self:set_animation("close") self:set_animation("close")
minetest.sound_play(self.sound_prefix .. "_close", {pos=self.node_pos, gain=0.3, max_hear_distance = 16}, true) minetest.sound_play(self.sound_prefix .. "_close",
{ pos = self.node_pos, gain = 0.3, max_hear_distance = 16 },
true)
self.is_open = false self.is_open = false
end end
end, end,
@ -136,7 +148,7 @@ minetest.register_entity("mcl_chests:chest", {
}) })
local function get_entity_pos(pos, dir, double) local function get_entity_pos(pos, dir, double)
pos = vector.new(pos) pos = vector.copy(pos)
if double then if double then
local add, mul, vec, cross = vector.add, vector.multiply, vector.new, vector.cross local add, mul, vec, cross = vector.add, vector.multiply, vector.new, vector.cross
pos = add(pos, mul(cross(dir, vec(0, 1, 0)), -0.5)) pos = add(pos, mul(cross(dir, vec(0, 1, 0)), -0.5))
@ -158,7 +170,8 @@ local function get_entity_info(pos, param2, double, dir, entity_pos)
return dir, get_entity_pos(pos, dir, double) return dir, get_entity_pos(pos, dir, double)
end end
local function create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir, entity_pos) local function create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir,
entity_pos)
dir, entity_pos = get_entity_info(pos, param2, double, dir, entity_pos) dir, entity_pos = get_entity_info(pos, param2, double, dir, entity_pos)
local obj = minetest.add_entity(entity_pos, "mcl_chests:chest") local obj = minetest.add_entity(entity_pos, "mcl_chests:chest")
local luaentity = obj:get_luaentity() local luaentity = obj:get_luaentity()
@ -166,9 +179,12 @@ local function create_entity(pos, node_name, textures, param2, double, sound_pre
return luaentity return luaentity
end end
local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir, entity_pos) local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type
, dir, entity_pos)
dir, entity_pos = get_entity_info(pos, param2, double, dir, entity_pos) dir, entity_pos = get_entity_info(pos, param2, double, dir, entity_pos)
return find_entity(entity_pos) or create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir, entity_pos) return find_entity(entity_pos) or
create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir,
entity_pos)
end end
local no_rotate, simple_rotate local no_rotate, simple_rotate
@ -179,7 +195,9 @@ if minetest.get_modpath("screwdriver") then
local nodename = node.name local nodename = node.name
local nodedef = minetest.registered_nodes[nodename] local nodedef = minetest.registered_nodes[nodename]
local dir = minetest.facedir_to_dir(new_param2) local dir = minetest.facedir_to_dir(new_param2)
find_or_create_entity(pos, nodename, nodedef._chest_entity_textures, new_param2, false, nodedef._chest_entity_sound, nodedef._chest_entity_mesh, nodedef._chest_entity_animation_type, dir):set_yaw(dir) find_or_create_entity(pos, nodename, nodedef._chest_entity_textures, new_param2, false,
nodedef._chest_entity_sound,
nodedef._chest_entity_mesh, nodedef._chest_entity_animation_type, dir):set_yaw(dir)
else else
return false return false
end end
@ -204,10 +222,21 @@ end]]
-- To be called if a player opened a chest -- To be called if a player opened a chest
local function player_chest_open(player, pos, node_name, textures, param2, double, sound, mesh, shulker) local function player_chest_open(player, pos, node_name, textures, param2, double, sound, mesh, shulker)
local name = player:get_player_name() local name = player:get_player_name()
open_chests[name] = {pos = pos, node_name = node_name, textures = textures, param2 = param2, double = double, sound = sound, mesh = mesh, shulker = shulker} open_chests[name] = {
pos = pos,
node_name = node_name,
textures = textures,
param2 = param2,
double = double,
sound = sound,
mesh = mesh,
shulker = shulker
}
if animate_chests then if animate_chests then
local dir = minetest.facedir_to_dir(param2) local dir = minetest.facedir_to_dir(param2)
find_or_create_entity(pos, node_name, textures, param2, double, sound, mesh, shulker and "shulker" or "chest", dir):open(name) find_or_create_entity(pos, node_name, textures, param2, double, sound, mesh, shulker and "shulker" or "chest",
dir):
open(name)
end end
end end
@ -221,6 +250,7 @@ local function protection_check_move(pos, from_list, from_index, to_list, to_ind
return count return count
end end
end end
local function protection_check_put_take(pos, listname, index, stack, player) local function protection_check_put_take(pos, listname, index, stack, player)
local name = player:get_player_name() local name = player:get_player_name()
if minetest.is_protected(pos, name) then if minetest.is_protected(pos, name) then
@ -239,11 +269,13 @@ local function chest_update_after_close(pos)
if node.name == "mcl_chests:trapped_chest_on_small" then if node.name == "mcl_chests:trapped_chest_on_small" then
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_small", param2 = node.param2 }) minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_small", param2 = node.param2 })
find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_small") find_or_create_entity(pos, "mcl_chests:trapped_chest_small", { "mcl_chests_trapped.png" }, node.param2, false,
"default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_small")
mesecon.receptor_off(pos, trapped_chest_mesecons_rules) mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
elseif node.name == "mcl_chests:trapped_chest_on_left" then elseif node.name == "mcl_chests:trapped_chest_on_left" then
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_left", param2 = node.param2 }) minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_left", param2 = node.param2 })
find_or_create_entity(pos, "mcl_chests:trapped_chest_left", tiles_chest_trapped_double, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left") find_or_create_entity(pos, "mcl_chests:trapped_chest_left", tiles_chest_trapped_double, node.param2, true,
"default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
mesecon.receptor_off(pos, trapped_chest_mesecons_rules) mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
@ -255,7 +287,8 @@ local function chest_update_after_close(pos)
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
minetest.swap_node(pos_other, { name = "mcl_chests:trapped_chest_left", param2 = node.param2 }) minetest.swap_node(pos_other, { name = "mcl_chests:trapped_chest_left", param2 = node.param2 })
find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", tiles_chest_trapped_double, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left") find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", tiles_chest_trapped_double, node.param2, true,
"default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules) mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
end end
end end
@ -268,7 +301,9 @@ local function player_chest_close(player)
return return
end end
if animate_chests then if animate_chests then
find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2, open_chest.double, open_chest.sound, open_chest.mesh, open_chest.shulker and "shulker" or "chest"):close(name) find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2,
open_chest.double,
open_chest.sound, open_chest.mesh, open_chest.shulker and "shulker" or "chest"):close(name)
end end
chest_update_after_close(open_chest.pos) chest_update_after_close(open_chest.pos)
@ -276,7 +311,9 @@ local function player_chest_close(player)
end end
-- This is a helper function to register both chests and trapped chests. Trapped chests will make use of the additional parameters -- This is a helper function to register both chests and trapped chests. Trapped chests will make use of the additional parameters
local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tiles_table, hidden, mesecons, on_rightclick_addendum, on_rightclick_addendum_left, on_rightclick_addendum_right, drop, canonical_basename) local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tiles_table, hidden, mesecons,
on_rightclick_addendum, on_rightclick_addendum_left, on_rightclick_addendum_right, drop,
canonical_basename)
-- START OF register_chest FUNCTION BODY -- START OF register_chest FUNCTION BODY
if not drop then if not drop then
drop = "mcl_chests:" .. basename drop = "mcl_chests:" .. basename
@ -361,10 +398,9 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
drawtype = "mesh", drawtype = "mesh",
mesh = "mcl_chests_chest.b3d", mesh = "mcl_chests_chest.b3d",
tiles = small_textures, tiles = small_textures,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, use_texture_alpha = "opaque",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
stack_max = 64,
sounds = mcl_sounds.node_sound_wood_defaults(), sounds = mcl_sounds.node_sound_wood_defaults(),
groups = { deco_block = 1 }, groups = { deco_block = 1 },
on_construct = function(pos, node) on_construct = function(pos, node)
@ -381,7 +417,8 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
local players = minetest.get_connected_players() local players = minetest.get_connected_players()
for p = 1, #players do for p = 1, #players do
if vector.distance(players[p]:get_pos(), pos) <= 30 then if vector.distance(players[p]:get_pos(), pos) <= 30 then
minetest.close_formspec(players[p]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z) minetest.close_formspec(players[p]:get_player_name(),
"mcl_chests:" .. canonical_basename .. "_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z)
end end
end end
end end
@ -398,16 +435,24 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
fixed = { -0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375 }, fixed = { -0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375 },
}, },
tiles = { "blank.png^[resize:16x16" }, tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = "clip",
_chest_entity_textures = small_textures, _chest_entity_textures = small_textures,
_chest_entity_sound = "default_chest", _chest_entity_sound = "default_chest",
_chest_entity_mesh = "mcl_chests_chest", _chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest", _chest_entity_animation_type = "chest",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
stack_max = 64,
drop = drop, drop = drop,
groups = {handy=1,axey=1, container=2, deco_block=1, material_wood=1,flammable=-1,chest_entity=1, not_in_creative_inventory=1}, groups = {
handy = 1,
axey = 1,
container = 2,
deco_block = 1,
material_wood = 1,
flammable = -1,
chest_entity = 1,
not_in_creative_inventory = 1
},
is_ground_content = false, is_ground_content = false,
sounds = mcl_sounds.node_sound_wood_defaults(), sounds = mcl_sounds.node_sound_wood_defaults(),
on_construct = function(pos) on_construct = function(pos)
@ -435,19 +480,26 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
-- BEGIN OF LISTRING WORKAROUND -- BEGIN OF LISTRING WORKAROUND
inv:set_size("input", 1) inv:set_size("input", 1)
-- END OF LISTRING WORKAROUND -- END OF LISTRING WORKAROUND
if minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "right")).name == "mcl_chests:"..canonical_basename.."_small" then if minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "right")).name ==
"mcl_chests:" .. canonical_basename .. "_small" then
minetest.swap_node(pos, { name = "mcl_chests:" .. canonical_basename .. "_right", param2 = param2 }) minetest.swap_node(pos, { name = "mcl_chests:" .. canonical_basename .. "_right", param2 = param2 })
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right") local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
minetest.swap_node(p, { name = "mcl_chests:" .. canonical_basename .. "_left", param2 = param2 }) minetest.swap_node(p, { name = "mcl_chests:" .. canonical_basename .. "_left", param2 = param2 })
create_entity(p, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true, "default_chest", "mcl_chests_chest", "chest") create_entity(p, "mcl_chests:" .. canonical_basename .. "_left", left_textures, param2, true,
elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..canonical_basename.."_small" then "default_chest",
"mcl_chests_chest", "chest")
elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name ==
"mcl_chests:" .. canonical_basename .. "_small" then
minetest.swap_node(pos, { name = "mcl_chests:" .. canonical_basename .. "_left", param2 = param2 }) minetest.swap_node(pos, { name = "mcl_chests:" .. canonical_basename .. "_left", param2 = param2 })
create_entity(pos, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true, "default_chest", "mcl_chests_chest", "chest") create_entity(pos, "mcl_chests:" .. canonical_basename .. "_left", left_textures, param2, true,
"default_chest",
"mcl_chests_chest", "chest")
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left") local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left")
minetest.swap_node(p, { name = "mcl_chests:" .. canonical_basename .. "_right", param2 = param2 }) minetest.swap_node(p, { name = "mcl_chests:" .. canonical_basename .. "_right", param2 = param2 })
else else
minetest.swap_node(pos, { name = "mcl_chests:" .. canonical_basename .. "_small", param2 = param2 }) minetest.swap_node(pos, { name = "mcl_chests:" .. canonical_basename .. "_small", param2 = param2 })
create_entity(pos, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest", "chest") create_entity(pos, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest",
"chest")
end end
end, end,
after_place_node = function(pos, placer, itemstack, pointed_thing) after_place_node = function(pos, placer, itemstack, pointed_thing)
@ -490,24 +542,31 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
end end
minetest.show_formspec(clicker:get_player_name(), minetest.show_formspec(clicker:get_player_name(),
"mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z, sf("mcl_chests:%s_%s_%s_%s", canonical_basename, pos.x, pos.y, pos.z),
"size[9,8.75]".. table.concat({
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]".. "formspec_version[4]",
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
"list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos.x, pos.y, pos.z),
"list[current_player;main;0,7.74;9,1;]".. "label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]".. "list[current_player;main;0.375,5.1;9,3;9]",
"listring[current_player;main]")
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]",
})
)
if on_rightclick_addendum then if on_rightclick_addendum then
on_rightclick_addendum(pos, node, clicker) on_rightclick_addendum(pos, node, clicker)
end end
player_chest_open(clicker, pos, small_name, small_textures, node.param2, false, "default_chest", "mcl_chests_chest") player_chest_open(clicker, pos, small_name, small_textures, node.param2, false, "default_chest",
"mcl_chests_chest")
end, end,
on_destruct = function(pos) on_destruct = function(pos)
@ -524,14 +583,23 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
fixed = { -0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375 }, fixed = { -0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375 },
}, },
tiles = { "blank.png^[resize:16x16" }, tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = "clip",
_chest_entity_textures = left_textures, _chest_entity_textures = left_textures,
_chest_entity_sound = "default_chest", _chest_entity_sound = "default_chest",
_chest_entity_mesh = "mcl_chests_chest", _chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest", _chest_entity_animation_type = "chest",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
groups = {handy=1,axey=1, container=5,not_in_creative_inventory=1, material_wood=1,flammable=-1,chest_entity=1,double_chest=1}, groups = {
handy = 1,
axey = 1,
container = 5,
not_in_creative_inventory = 1,
material_wood = 1,
flammable = -1,
chest_entity = 1,
double_chest = 1
},
drop = drop, drop = drop,
is_ground_content = false, is_ground_content = false,
sounds = mcl_sounds.node_sound_wood_defaults(), sounds = mcl_sounds.node_sound_wood_defaults(),
@ -590,7 +658,8 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
else else
return 0 return 0
end end
end]]-- end]]
--
-- END OF LISTRING WORKAROUND -- END OF LISTRING WORKAROUND
else else
return stack:get_count() return stack:get_count()
@ -625,7 +694,8 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
local above_def = minetest.registered_nodes[minetest.get_node({ x = pos.x, y = pos.y + 1, z = pos.z }).name] local above_def = minetest.registered_nodes[minetest.get_node({ x = pos.x, y = pos.y + 1, z = pos.z }).name]
local above_def_other = minetest.registered_nodes[minetest.get_node({x = pos_other.x, y = pos_other.y + 1, z = pos_other.z}).name] local above_def_other = minetest.registered_nodes[
minetest.get_node({ x = pos_other.x, y = pos_other.y + 1, z = pos_other.z }).name]
if not above_def or above_def.groups.opaque == 1 or not above_def_other or above_def_other.groups.opaque == 1 then if not above_def or above_def.groups.opaque == 1 or not above_def_other or above_def_other.groups.opaque == 1 then
-- won't open if there is no space from the top -- won't open if there is no space from the top
@ -641,32 +711,40 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
end end
minetest.show_formspec(clicker:get_player_name(), minetest.show_formspec(clicker:get_player_name(),
"mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z, sf("mcl_chests:%s_%s_%s_%s", canonical_basename, pos.x, pos.y, pos.z),
"size[9,11.5]".. table.concat({
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]".. "formspec_version[4]",
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]".. "size[11.75,14.15]",
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"list[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main;0,3.5;9,3;]".. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg(0,3.5,9,3).. mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"label[0,7;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos.x, pos.y, pos.z),
"list[current_player;main;0,7.5;9,3;9]".. mcl_formspec.get_itemslot_bg_v4(0.375, 4.5, 9, 3),
mcl_formspec.get_itemslot_bg(0,7.5,9,3).. sf("list[nodemeta:%s,%s,%s;main;0.375,4.5;9,3;]", pos_other.x, pos_other.y, pos_other.z),
"list[current_player;main;0,10.75;9,1;]".. "label[0.375,8.45;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg(0,10.75,9,1).. mcl_formspec.get_itemslot_bg_v4(0.375, 8.825, 9, 3),
"list[current_player;main;0.375,8.825;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 12.775, 9, 1),
"list[current_player;main;0.375,12.775;9,1;]",
--BEGIN OF LISTRING WORKAROUND --BEGIN OF LISTRING WORKAROUND
"listring[current_player;main]".. "listring[current_player;main]",
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";input]".. sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND --END OF LISTRING WORKAROUND
"listring[current_player;main]" .. "listring[current_player;main]" ..
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]".. sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]".. "listring[current_player;main]",
"listring[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main]") sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
})
)
if on_rightclick_addendum_left then if on_rightclick_addendum_left then
on_rightclick_addendum_left(pos, node, clicker) on_rightclick_addendum_left(pos, node, clicker)
end end
player_chest_open(clicker, pos, left_name, left_textures, node.param2, true, "default_chest", "mcl_chests_chest") player_chest_open(clicker, pos, left_name, left_textures, node.param2, true, "default_chest",
"mcl_chests_chest")
end, end,
mesecons = mesecons, mesecons = mesecons,
on_rotate = no_rotate, on_rotate = no_rotate,
@ -681,8 +759,16 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
fixed = { -0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375 }, fixed = { -0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375 },
}, },
tiles = { "blank.png^[resize:16x16" }, tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = "clip",
groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2}, groups = {
handy = 1,
axey = 1,
container = 6,
not_in_creative_inventory = 1,
material_wood = 1,
flammable = -1,
double_chest = 2
},
drop = drop, drop = drop,
is_ground_content = false, is_ground_content = false,
sounds = mcl_sounds.node_sound_wood_defaults(), sounds = mcl_sounds.node_sound_wood_defaults(),
@ -773,8 +859,10 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
if minetest.registered_nodes[minetest.get_node({x = pos.x, y = pos.y + 1, z = pos.z}).name].groups.opaque == 1 if minetest.registered_nodes[minetest.get_node(vector.offset(pos, 0, 1, 0)).name].groups.opaque == 1
or minetest.registered_nodes[minetest.get_node({x = pos_other.x, y = pos_other.y + 1, z = pos_other.z}).name].groups.opaque == 1 then or
minetest.registered_nodes[minetest.get_node(vector.offset(pos_other, 0, 1, 0)).name].groups.opaque
== 1 then
-- won't open if there is no space from the top -- won't open if there is no space from the top
return false return false
end end
@ -788,33 +876,40 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
end end
minetest.show_formspec(clicker:get_player_name(), minetest.show_formspec(clicker:get_player_name(),
"mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z, sf("mcl_chests:%s_%s_%s_%s", canonical_basename, pos.x, pos.y, pos.z),
table.concat({
"formspec_version[4]",
"size[11.75,14.15]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos_other.x, pos_other.y, pos_other.z),
mcl_formspec.get_itemslot_bg_v4(0.375, 4.5, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,4.5;9,3;]", pos.x, pos.y, pos.z),
"label[0.375,8.45;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 8.825, 9, 3),
"list[current_player;main;0.375,8.825;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 12.775, 9, 1),
"list[current_player;main;0.375,12.775;9,1;]",
"size[9,11.5]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]"..
"list[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main;0,0.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,3.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,3.5,9,3)..
"label[0,7;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,7.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,7.5,9,3)..
"list[current_player;main;0,10.75;9,1;]"..
mcl_formspec.get_itemslot_bg(0,10.75,9,1)..
--BEGIN OF LISTRING WORKAROUND --BEGIN OF LISTRING WORKAROUND
"listring[current_player;main]".. "listring[current_player;main]",
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";input]".. sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND --END OF LISTRING WORKAROUND
"listring[current_player;main]" .. "listring[current_player;main]" ..
"listring[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main]".. sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
"listring[current_player;main]".. "listring[current_player;main]",
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]") sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
})
)
if on_rightclick_addendum_right then if on_rightclick_addendum_right then
on_rightclick_addendum_right(pos, node, clicker) on_rightclick_addendum_right(pos, node, clicker)
end end
player_chest_open(clicker, pos_other, left_name, left_textures, node.param2, true, "default_chest", "mcl_chests_chest") player_chest_open(clicker, pos_other, left_name, left_textures, node.param2, true, "default_chest",
"mcl_chests_chest")
end, end,
mesecons = mesecons, mesecons = mesecons,
on_rotate = no_rotate, on_rotate = no_rotate,
@ -838,6 +933,15 @@ register_chest("chest",
{ {
small = tiles_chest_normal_small, small = tiles_chest_normal_small,
double = tiles_chest_normal_double, double = tiles_chest_normal_double,
inv = { "default_chest_top.png", "mcl_chests_chest_bottom.png",
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
"mcl_chests_chest_back.png", "default_chest_front.png" },
--[[left = {"default_chest_top_big.png", "default_chest_top_big.png",
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
"default_chest_side_big.png^[transformFX", "default_chest_front_big.png"},
right = {"default_chest_top_big.png^[transformFX", "default_chest_top_big.png^[transformFX",
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
"default_chest_side_big.png", "default_chest_front_big.png^[transformFX"},]] --
}, },
false false
) )
@ -851,16 +955,20 @@ register_chest("trapped_chest",
S("Trapped Chest"), S("Trapped Chest"),
S("A trapped chest is a container which provides 27 inventory slots. When it is opened, it sends a redstone signal to its adjacent blocks as long it stays open. Trapped chests can be turned into large trapped chests with double the capacity by placing two trapped chests next to each other."), S("A trapped chest is a container which provides 27 inventory slots. When it is opened, it sends a redstone signal to its adjacent blocks as long it stays open. Trapped chests can be turned into large trapped chests with double the capacity by placing two trapped chests next to each other."),
chestusage, chestusage,
S("27 inventory slots") .. "\n" .. S("Can be combined to a large chest") .. "\n" .. S("Emits a redstone signal when opened"), S("27 inventory slots") ..
"\n" .. S("Can be combined to a large chest") .. "\n" .. S("Emits a redstone signal when opened"),
traptiles, traptiles,
nil, nil,
{receptor = { {
receptor = {
state = mesecon.state.off, state = mesecon.state.off,
rules = trapped_chest_mesecons_rules, rules = trapped_chest_mesecons_rules,
}}, },
},
function(pos, node, clicker) function(pos, node, clicker)
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_on_small", param2 = node.param2 }) minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_on_small", param2 = node.param2 })
find_or_create_entity(pos, "mcl_chests:trapped_chest_on_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_small") find_or_create_entity(pos, "mcl_chests:trapped_chest_on_small", { "mcl_chests_trapped.png" }, node.param2, false,
"default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_small")
mesecon.receptor_on(pos, trapped_chest_mesecons_rules) mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
end, end,
function(pos, node, clicker) function(pos, node, clicker)
@ -868,7 +976,8 @@ register_chest("trapped_chest",
meta:set_int("players", 1) meta:set_int("players", 1)
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_on_left", param2 = node.param2 }) minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_on_left", param2 = node.param2 })
find_or_create_entity(pos, "mcl_chests:trapped_chest_on_left", tiles_chest_trapped_double, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_left") find_or_create_entity(pos, "mcl_chests:trapped_chest_on_left", tiles_chest_trapped_double, node.param2, true,
"default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_left")
mesecon.receptor_on(pos, trapped_chest_mesecons_rules) mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
@ -882,17 +991,21 @@ register_chest("trapped_chest",
mesecon.receptor_on(pos, trapped_chest_mesecons_rules) mesecon.receptor_on(pos, trapped_chest_mesecons_rules)
minetest.swap_node(pos_other, { name = "mcl_chests:trapped_chest_on_left", param2 = node.param2 }) minetest.swap_node(pos_other, { name = "mcl_chests:trapped_chest_on_left", param2 = node.param2 })
find_or_create_entity(pos_other, "mcl_chests:trapped_chest_on_left", tiles_chest_trapped_double, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_left") find_or_create_entity(pos_other, "mcl_chests:trapped_chest_on_left", tiles_chest_trapped_double, node.param2,
true,
"default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_on_left")
mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules) mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules)
end end
) )
register_chest("trapped_chest_on", register_chest("trapped_chest_on",
nil, nil, nil, nil, traptiles, true, nil, nil, nil, nil, traptiles, true,
{receptor = { {
receptor = {
state = mesecon.state.on, state = mesecon.state.on,
rules = trapped_chest_mesecons_rules, rules = trapped_chest_mesecons_rules,
}}, },
},
nil, nil, nil, nil, nil, nil,
"trapped_chest", "trapped_chest",
"trapped_chest" "trapped_chest"
@ -949,59 +1062,68 @@ minetest.register_craft({
{ "group:wood", "group:wood", "group:wood" }, { "group:wood", "group:wood", "group:wood" },
{ "group:wood", "", "group:wood" }, { "group:wood", "", "group:wood" },
{ "group:wood", "group:wood", "group:wood" }, { "group:wood", "group:wood", "group:wood" },
} },
}) })
minetest.register_craft({ minetest.register_craft({
type = "fuel", type = "fuel",
recipe = "mcl_chests:chest", recipe = "mcl_chests:chest",
burntime = 15 burntime = 15,
}) })
minetest.register_craft({ minetest.register_craft({
type = "fuel", type = "fuel",
recipe = "mcl_chests:trapped_chest", recipe = "mcl_chests:trapped_chest",
burntime = 15 burntime = 15,
}) })
minetest.register_node("mcl_chests:ender_chest", { minetest.register_node("mcl_chests:ender_chest", {
description = S("Ender Chest"), description = S("Ender Chest"),
_tt_help = S("27 interdimensional inventory slots") .. "\n" .. S("Put items inside, retrieve them from any ender chest"), _tt_help = S("27 interdimensional inventory slots") ..
_doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."), "\n" .. S("Put items inside, retrieve them from any ender chest"),
_doc_items_longdesc = S(
"Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."),
_doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."), _doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
drawtype = "mesh", drawtype = "mesh",
mesh = "mcl_chests_chest.b3d", mesh = "mcl_chests_chest.b3d",
tiles = tiles_chest_ender_small, tiles = tiles_chest_ender_small,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, use_texture_alpha = "opaque",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
stack_max = 64,
groups = { deco_block = 1 }, groups = { deco_block = 1 },
sounds = mcl_sounds.node_sound_stone_defaults(), sounds = mcl_sounds.node_sound_stone_defaults(),
on_construct = function(pos, node) on_construct = function(pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
node.name = "mcl_chests:ender_chest_small" node.name = "mcl_chests:ender_chest_small"
minetest.set_node(pos, node) minetest.set_node(pos, node)
end, end,
}) })
local formspec_ender_chest = "size[9,8.75]".. local formspec_ender_chest = table.concat({
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Ender Chest"))).."]".. "formspec_version[4]",
"list[current_player;enderchest;0,0.5;9,3;]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Ender Chest"))) .. "]",
"list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;enderchest;0.375,0.75;9,3;]",
"list[current_player;main;0,7.74;9,1;]".. "label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"listring[current_player;enderchest]".. "list[current_player;main;0.375,5.1;9,3;9]",
"listring[current_player;main]"
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[current_player;enderchest]",
"listring[current_player;main]",
})
minetest.register_node("mcl_chests:ender_chest_small", { minetest.register_node("mcl_chests:ender_chest_small", {
description = S("Ender Chest"), description = S("Ender Chest"),
_tt_help = S("27 interdimensional inventory slots") .. "\n" .. S("Put items inside, retrieve them from any ender chest"), _tt_help = S("27 interdimensional inventory slots") ..
_doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."), "\n" .. S("Put items inside, retrieve them from any ender chest"),
_doc_items_longdesc = S(
"Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."),
_doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."), _doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
drawtype = "nodebox", drawtype = "nodebox",
node_box = { node_box = {
@ -1013,7 +1135,7 @@ minetest.register_node("mcl_chests:ender_chest_small", {
_chest_entity_mesh = "mcl_chests_chest", _chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest", _chest_entity_animation_type = "chest",
tiles = { "blank.png^[resize:16x16" }, tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = "clip",
-- Note: The “container” group is missing here because the ender chest does not -- Note: The “container” group is missing here because the ender chest does not
-- have an inventory on its own -- have an inventory on its own
groups = { pickaxey = 1, deco_block = 1, material_stone = 1, chest_entity = 1, not_in_creative_inventory = 1 }, groups = { pickaxey = 1, deco_block = 1, material_stone = 1, chest_entity = 1, not_in_creative_inventory = 1 },
@ -1024,15 +1146,18 @@ minetest.register_node("mcl_chests:ender_chest_small", {
sounds = mcl_sounds.node_sound_stone_defaults(), sounds = mcl_sounds.node_sound_stone_defaults(),
drop = "mcl_core:obsidian 8", drop = "mcl_core:obsidian 8",
on_construct = function(pos) on_construct = function(pos)
create_entity(pos, "mcl_chests:ender_chest_small", ender_chest_texture, minetest.get_node(pos).param2, false, "mcl_chests_enderchest", "mcl_chests_chest", "chest") create_entity(pos, "mcl_chests:ender_chest_small", ender_chest_texture, minetest.get_node(pos).param2, false,
"mcl_chests_enderchest", "mcl_chests_chest", "chest")
end, end,
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
if minetest.registered_nodes[minetest.get_node({x = pos.x, y = pos.y + 1, z = pos.z}).name].groups.opaque == 1 then if minetest.registered_nodes[minetest.get_node(vector.offset(pos, 0, 1, 0)).name].groups.opaque == 1 then
-- won't open if there is no space from the top -- won't open if there is no space from the top
return false return false
end end
minetest.show_formspec(clicker:get_player_name(), "mcl_chests:ender_chest_"..clicker:get_player_name(), formspec_ender_chest) minetest.show_formspec(clicker:get_player_name(), "mcl_chests:ender_chest_" .. clicker:get_player_name(),
player_chest_open(clicker, pos, "mcl_chests:ender_chest_small", ender_chest_texture, node.param2, false, "mcl_chests_enderchest", "mcl_chests_chest") formspec_ender_chest)
player_chest_open(clicker, pos, "mcl_chests:ender_chest_small", ender_chest_texture, node.param2, false,
"mcl_chests_enderchest", "mcl_chests_chest")
end, end,
on_receive_fields = function(pos, formname, fields, sender) on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then if fields.quit then
@ -1070,7 +1195,7 @@ minetest.register_craft({
{ "mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian" }, { "mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian" },
{ "mcl_core:obsidian", "mcl_end:ender_eye", "mcl_core:obsidian" }, { "mcl_core:obsidian", "mcl_end:ender_eye", "mcl_core:obsidian" },
{ "mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian" }, { "mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian" },
} },
}) })
-- Shulker boxes -- Shulker boxes
@ -1113,21 +1238,29 @@ local shulker_mob_textures = {
} }
local canonical_shulker_color = "violet" local canonical_shulker_color = "violet"
--WARNING: after formspec v4 update, old shulker boxes will need to be placed again to get the new formspec
local function formspec_shulker_box(name) local function formspec_shulker_box(name)
if name == "" then if not name or name == "" then
name = S("Shulker Box") name = S("Shulker Box")
end end
return "size[9,8.75]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]".. return table.concat({
"list[context;main;0,0.5;9,3;]".. "formspec_version[4]",
mcl_formspec.get_itemslot_bg(0,0.5,9,3).. "size[11.75,10.425]",
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,4.5;9,3;9]".. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"list[current_player;main;0,7.74;9,1;]".. "list[context;main;0.375,0.75;9,3;]",
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. "label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
"listring[context;main]".. mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"listring[current_player;main]" "list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[context;main]",
"listring[current_player;main]",
})
end end
local function set_shulkerbox_meta(nmeta, imeta) local function set_shulkerbox_meta(nmeta, imeta)
@ -1143,8 +1276,10 @@ for color, desc in pairs(boxtypes) do
local longdesc, usagehelp, create_entry, entry_name local longdesc, usagehelp, create_entry, entry_name
if mod_doc then if mod_doc then
if is_canonical then if is_canonical then
longdesc = S("A shulker box is a portable container which provides 27 inventory slots for any item except shulker boxes. Shulker boxes keep their inventory when broken, so shulker boxes as well as their contents can be taken as a single item. Shulker boxes come in many different colors.") longdesc = S(
usagehelp = S("To access the inventory of a shulker box, place and right-click it. To take a shulker box and its contents with you, just break and collect it, the items will not fall out. Place the shulker box again to be able to retrieve its contents.") "A shulker box is a portable container which provides 27 inventory slots for any item except shulker boxes. Shulker boxes keep their inventory when broken, so shulker boxes as well as their contents can be taken as a single item. Shulker boxes come in many different colors.")
usagehelp = S(
"To access the inventory of a shulker box, place and right-click it. To take a shulker box and its contents with you, just break and collect it, the items will not fall out. Place the shulker box again to be able to retrieve its contents.")
entry_name = S("Shulker Box") entry_name = S("Shulker Box")
else else
create_entry = false create_entry = false
@ -1161,10 +1296,18 @@ for color, desc in pairs(boxtypes) do
_doc_items_longdesc = longdesc, _doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp, _doc_items_usagehelp = usagehelp,
tiles = { mob_texture }, tiles = { mob_texture },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, use_texture_alpha = "opaque",
drawtype = "mesh", drawtype = "mesh",
mesh = "mcl_chests_shulker.b3d", mesh = "mcl_chests_shulker.b3d",
groups = {handy=1,pickaxey=1, container=3, deco_block=1, dig_by_piston=1, shulker_box=1, old_shulker_box_node=1}, groups = {
handy = 1,
pickaxey = 1,
container = 3,
deco_block = 1,
dig_by_piston = 1,
shulker_box = 1,
old_shulker_box_node = 1
},
is_ground_content = false, is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(), sounds = mcl_sounds.node_sound_stone_defaults(),
stack_max = 1, stack_max = 1,
@ -1224,12 +1367,21 @@ for color, desc in pairs(boxtypes) do
fixed = { -0.48, -0.5, -0.48, 0.48, 0.489, 0.48 }, fixed = { -0.48, -0.5, -0.48, 0.48, 0.489, 0.48 },
}, },
tiles = { "blank.png^[resize:16x16" }, tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, use_texture_alpha = "clip",
_chest_entity_textures = { mob_texture }, _chest_entity_textures = { mob_texture },
_chest_entity_sound = "mcl_chests_shulker", _chest_entity_sound = "mcl_chests_shulker",
_chest_entity_mesh = "mcl_chests_shulker", _chest_entity_mesh = "mcl_chests_shulker",
_chest_entity_animation_type = "shulker", _chest_entity_animation_type = "shulker",
groups = {handy=1,pickaxey=1, container=3, deco_block=1, dig_by_piston=1, shulker_box=1, chest_entity=1, not_in_creative_inventory=1}, groups = {
handy = 1,
pickaxey = 1,
container = 3,
deco_block = 1,
dig_by_piston = 1,
shulker_box = 1,
chest_entity = 1,
not_in_creative_inventory = 1
},
is_ground_content = false, is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(), sounds = mcl_sounds.node_sound_stone_defaults(),
stack_max = 1, stack_max = 1,
@ -1244,7 +1396,8 @@ for color, desc in pairs(boxtypes) do
meta:set_string("formspec", formspec_shulker_box(nil)) meta:set_string("formspec", formspec_shulker_box(nil))
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size("main", 9 * 3) inv:set_size("main", 9 * 3)
create_entity(pos, small_name, {mob_texture}, minetest.get_node(pos).param2, false, "mcl_chests_shulker", "mcl_chests_shulker", "shulker") create_entity(pos, small_name, { mob_texture }, minetest.get_node(pos).param2, false, "mcl_chests_shulker",
"mcl_chests_shulker", "shulker")
end, end,
after_place_node = function(pos, placer, itemstack, pointed_thing) after_place_node = function(pos, placer, itemstack, pointed_thing)
local nmeta = minetest.get_meta(pos) local nmeta = minetest.get_meta(pos)
@ -1266,7 +1419,8 @@ for color, desc in pairs(boxtypes) do
end end
end, end,
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
player_chest_open(clicker, pos, small_name, {mob_texture}, node.param2, false, "mcl_chests_shulker", "mcl_chests_shulker", true) player_chest_open(clicker, pos, small_name, { mob_texture }, node.param2, false, "mcl_chests_shulker",
"mcl_chests_shulker", true)
end, end,
on_receive_fields = function(pos, formname, fields, sender) on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then if fields.quit then
@ -1317,14 +1471,16 @@ for color, desc in pairs(boxtypes) do
}) })
if mod_doc and not is_canonical then if mod_doc and not is_canonical then
doc.add_entry_alias("nodes", "mcl_chests:"..canonical_shulker_color.."_shulker_box", "nodes", "mcl_chests:"..color.."_shulker_box") doc.add_entry_alias("nodes", "mcl_chests:" .. canonical_shulker_color .. "_shulker_box", "nodes",
doc.add_entry_alias("nodes", "mcl_chests:"..canonical_shulker_color.."_shulker_box_small", "nodes", "mcl_chests:"..color.."_shulker_box_small") "mcl_chests:" .. color .. "_shulker_box")
doc.add_entry_alias("nodes", "mcl_chests:" .. canonical_shulker_color .. "_shulker_box_small", "nodes",
"mcl_chests:" .. color .. "_shulker_box_small")
end end
minetest.register_craft({ minetest.register_craft({
type = "shapeless", type = "shapeless",
output = "mcl_chests:" .. color .. "_shulker_box", output = "mcl_chests:" .. color .. "_shulker_box",
recipe = { "group:shulker_box", "mcl_dye:"..color } recipe = { "group:shulker_box", "mcl_dye:" .. color },
}) })
end end
@ -1334,7 +1490,7 @@ minetest.register_craft({
{ "mcl_mobitems:shulker_shell" }, { "mcl_mobitems:shulker_shell" },
{ "mcl_chests:chest" }, { "mcl_chests:chest" },
{ "mcl_mobitems:shulker_shell" }, { "mcl_mobitems:shulker_shell" },
} },
}) })
-- Save metadata of shulker box when used in crafting -- Save metadata of shulker box when used in crafting
@ -1362,7 +1518,8 @@ local function select_and_spawn_entity(pos, node)
local node_name = node.name local node_name = node.name
local node_def = minetest.registered_nodes[node_name] local node_def = minetest.registered_nodes[node_name]
local double_chest = minetest.get_item_group(node_name, "double_chest") > 0 local double_chest = minetest.get_item_group(node_name, "double_chest") > 0
find_or_create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest, node_def._chest_entity_sound, node_def._chest_entity_mesh, node_def._chest_entity_animation_type) find_or_create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest,
node_def._chest_entity_sound, node_def._chest_entity_mesh, node_def._chest_entity_animation_type)
end end
minetest.register_lbm({ minetest.register_lbm({
@ -1376,7 +1533,9 @@ minetest.register_lbm({
minetest.register_lbm({ minetest.register_lbm({
label = "Replace old chest nodes", label = "Replace old chest nodes",
name = "mcl_chests:replace_old", name = "mcl_chests:replace_old",
nodenames = {"mcl_chests:chest", "mcl_chests:trapped_chest", "mcl_chests:trapped_chest_on", "mcl_chests:ender_chest", "group:old_shulker_box_node"}, nodenames = { "mcl_chests:chest", "mcl_chests:trapped_chest", "mcl_chests:trapped_chest_on",
"mcl_chests:ender_chest",
"group:old_shulker_box_node" },
run_at_every_load = true, run_at_every_load = true,
action = function(pos, node) action = function(pos, node)
local node_name = node.name local node_name = node.name
@ -1399,7 +1558,8 @@ minetest.register_lbm({
-- Fixes redstone weirdness. -- Fixes redstone weirdness.
label = "Disable active trapped chests", label = "Disable active trapped chests",
name = "mcl_chests:reset_trapped_chests", name = "mcl_chests:reset_trapped_chests",
nodenames = { "mcl_chests:trapped_chest_on_small", "mcl_chests:trapped_chest_on_left", "mcl_chests:trapped_chest_on_right" }, nodenames = { "mcl_chests:trapped_chest_on_small", "mcl_chests:trapped_chest_on_left",
"mcl_chests:trapped_chest_on_right" },
run_at_every_load = true, run_at_every_load = true,
action = function(pos, node) action = function(pos, node)
minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " .. minetest.pos_to_string(pos)) minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " .. minetest.pos_to_string(pos))
@ -1408,13 +1568,13 @@ minetest.register_lbm({
}) })
minetest.register_lbm({ minetest.register_lbm({
label = "Update shulker box formspecs (0.60.0)", label = "Update shulker box formspecs (0.72.0)",
name = "mcl_chests:update_shulker_box_formspecs_0_60_0", name = "mcl_chests:update_shulker_box_formspecs_0_72_0",
nodenames = { "group:shulker_box" }, nodenames = { "group:shulker_box" },
run_at_every_load = false, run_at_every_load = false,
action = function(pos, node) action = function(pos, node)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("formspec", formspec_shulker_box) meta:set_string("formspec", formspec_shulker_box(meta:get_string("name")))
end, end,
}) })

View file

@ -1,34 +1,51 @@
---@diagnostic disable lowercase-global
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local formspec_escape = minetest.formspec_escape local F = minetest.formspec_escape
local show_formspec = minetest.show_formspec
local C = minetest.colorize local C = minetest.colorize
local text_color = "#313131" local show_formspec = minetest.show_formspec
local itemslot_bg = mcl_formspec.get_itemslot_bg
mcl_crafting_table = {} mcl_crafting_table = {}
function mcl_crafting_table.show_crafting_form(player) mcl_crafting_table.formspec = table.concat({
player:get_inventory():set_width("craft", 3) "formspec_version[4]",
player:get_inventory():set_size("craft", 9) "size[11.75,10.425]",
show_formspec(player:get_player_name(), "main", "label[2.25,0.375;" .. F(C(mcl_formspec.label_color, S("Crafting"))) .. "]",
"size[9,8.75]"..
"image[4.7,1.5;1.5,1;gui_crafting_arrow.png]".. mcl_formspec.get_itemslot_bg_v4(2.25, 0.75, 3, 3),
"label[0,4;"..formspec_escape(C(text_color, S("Inventory"))).."]".. "list[current_player;craft;2.25,0.75;3,3;]",
"list[current_player;main;0,4.5;9,3;9]"..
itemslot_bg(0,4.5,9,3).. "image[6.125,2;1.5,1;gui_crafting_arrow.png]",
"list[current_player;main;0,7.74;9,1;]"..
itemslot_bg(0,7.74,9,1).. mcl_formspec.get_itemslot_bg_v4(8.2, 2, 1, 1, 0.2),
"label[1.75,0;"..formspec_escape(C(text_color, S("Crafting"))).."]".. "list[current_player;craftpreview;8.2,2;1,1;]",
"list[current_player;craft;1.75,0.5;3,3;]"..
itemslot_bg(1.75,0.5,3,3).. "label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
"list[current_player;craftpreview;6.1,1.5;1,1;]"..
itemslot_bg(6.1,1.5,1,1).. mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"image_button[0.75,1.5;1,1;craftguide_book.png;__mcl_craftguide;]".. "list[current_player;main;0.375,5.1;9,3;9]",
"tooltip[__mcl_craftguide;"..formspec_escape(S("Recipe book")).."]"..
"listring[current_player;main]".. mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"listring[current_player;craft]" "list[current_player;main;0.375,9.05;9,1;]",
)
"listring[current_player;craft]",
"listring[current_player;main]",
--Crafting guide button
"image_button[0.325,1.95;1.1,1.1;craftguide_book.png;__mcl_craftguide;]",
"tooltip[__mcl_craftguide;" .. F(S("Recipe book")) .. "]",
})
---@param player ObjectRef
function mcl_crafting_table.show_crafting_form(player)
local inv = player:get_inventory()
if inv then
inv:set_width("craft", 3)
inv:set_size("craft", 9)
end
show_formspec(player:get_player_name(), "main", mcl_crafting_table.formspec)
end end
minetest.register_node("mcl_crafting_table:crafting_table", { minetest.register_node("mcl_crafting_table:crafting_table", {
@ -57,7 +74,7 @@ minetest.register_craft({
recipe = { recipe = {
{ "group:wood", "group:wood" }, { "group:wood", "group:wood" },
{ "group:wood", "group:wood" } { "group:wood", "group:wood" }
} },
}) })
minetest.register_craft({ minetest.register_craft({

View file

@ -2,7 +2,8 @@ local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape local F = minetest.formspec_escape
function mcl_enchanting.is_book(itemname) function mcl_enchanting.is_book(itemname)
return itemname == "mcl_books:book" or itemname == "mcl_enchanting:book_enchanted" or itemname == "mcl_books:book_enchanted" return itemname == "mcl_books:book" or itemname == "mcl_enchanting:book_enchanted" or
itemname == "mcl_books:book_enchanted"
end end
function mcl_enchanting.get_enchantments(itemstack) function mcl_enchanting.get_enchantments(itemstack)
@ -54,11 +55,13 @@ end
function mcl_enchanting.get_enchantment_description(enchantment, level) function mcl_enchanting.get_enchantment_description(enchantment, level)
local enchantment_def = mcl_enchanting.enchantments[enchantment] local enchantment_def = mcl_enchanting.enchantments[enchantment]
return enchantment_def.name .. (enchantment_def.max_level == 1 and "" or " " .. mcl_enchanting.roman_numerals.toRoman(level)) return enchantment_def.name ..
(enchantment_def.max_level == 1 and "" or " " .. mcl_enchanting.roman_numerals.toRoman(level))
end end
function mcl_enchanting.get_colorized_enchantment_description(enchantment, level) function mcl_enchanting.get_colorized_enchantment_description(enchantment, level)
return minetest.colorize(mcl_enchanting.enchantments[enchantment].curse and mcl_colors.RED or mcl_colors.GRAY, mcl_enchanting.get_enchantment_description(enchantment, level)) return minetest.colorize(mcl_enchanting.enchantments[enchantment].curse and mcl_colors.RED or mcl_colors.GRAY,
mcl_enchanting.get_enchantment_description(enchantment, level))
end end
function mcl_enchanting.get_enchanted_itemstring(itemname) function mcl_enchanting.get_enchanted_itemstring(itemname)
@ -79,7 +82,8 @@ function mcl_enchanting.not_enchantable_on_enchanting_table(itemname)
end end
function mcl_enchanting.is_enchantable(itemname) function mcl_enchanting.is_enchantable(itemname)
return mcl_enchanting.get_enchantability(itemname) > 0 or mcl_enchanting.not_enchantable_on_enchanting_table(itemname) return mcl_enchanting.get_enchantability(itemname) > 0 or
mcl_enchanting.not_enchantable_on_enchanting_table(itemname)
end end
function mcl_enchanting.can_enchant_freshly(itemname) function mcl_enchanting.can_enchant_freshly(itemname)
@ -150,7 +154,8 @@ function mcl_enchanting.can_enchant(itemstack, enchantment, level)
for incompatible in pairs(enchantment_def.incompatible) do for incompatible in pairs(enchantment_def.incompatible) do
local incompatible_level = item_enchantments[incompatible] local incompatible_level = item_enchantments[incompatible]
if incompatible_level then if incompatible_level then
return false, "incompatible", mcl_enchanting.get_enchantment_description(incompatible, incompatible_level) return false, "incompatible",
mcl_enchanting.get_enchantment_description(incompatible, incompatible_level)
end end
end end
end end
@ -169,7 +174,9 @@ function mcl_enchanting.combine(itemstack, combine_with)
local itemname = itemstack:get_name() local itemname = itemstack:get_name()
local combine_name = combine_with:get_name() local combine_name = combine_with:get_name()
local enchanted_itemname = mcl_enchanting.get_enchanted_itemstring(itemname) local enchanted_itemname = mcl_enchanting.get_enchanted_itemstring(itemname)
if not enchanted_itemname or enchanted_itemname ~= mcl_enchanting.get_enchanted_itemstring(combine_name) and not mcl_enchanting.is_book(combine_name) then if not enchanted_itemname or
enchanted_itemname ~= mcl_enchanting.get_enchanted_itemstring(combine_name) and
not mcl_enchanting.is_book(combine_name) then
return false return false
end end
local enchantments = mcl_enchanting.get_enchantments(itemstack) local enchantments = mcl_enchanting.get_enchantments(itemstack)
@ -328,20 +335,24 @@ function mcl_enchanting.get_random_enchantment(itemstack, treasure, weighted, ex
return #possible > 0 and possible[mcl_enchanting.random(pr, 1, #possible)] return #possible > 0 and possible[mcl_enchanting.random(pr, 1, #possible)]
end end
function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr) function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance,
ignore_already_enchanted, pr)
local itemname = itemstack:get_name() local itemname = itemstack:get_name()
if (not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted) or mcl_enchanting.not_enchantable_on_enchanting_table(itemname) then if (not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted) or
mcl_enchanting.not_enchantable_on_enchanting_table(itemname) then
return return
end end
itemstack = ItemStack(itemstack) itemstack = ItemStack(itemstack)
local enchantability = minetest.get_item_group(itemname, "enchantability") local enchantability = minetest.get_item_group(itemname, "enchantability")
enchantability = 1 + mcl_enchanting.random(pr, 0, math.floor(enchantability / 4)) + mcl_enchanting.random(pr, 0, math.floor(enchantability / 4)) enchantability = 1 + mcl_enchanting.random(pr, 0, math.floor(enchantability / 4)) +
mcl_enchanting.random(pr, 0, math.floor(enchantability / 4))
enchantment_level = enchantment_level + enchantability enchantment_level = enchantment_level + enchantability
enchantment_level = enchantment_level + enchantment_level * (mcl_enchanting.random(pr) + mcl_enchanting.random(pr) - 1) * 0.15 enchantment_level = enchantment_level +
enchantment_level * (mcl_enchanting.random(pr) + mcl_enchanting.random(pr) - 1) * 0.15
enchantment_level = math.max(math.floor(enchantment_level + 0.5), 1) enchantment_level = math.max(math.floor(enchantment_level + 0.5), 1)
local enchantments = {} local enchantments = {}
@ -387,7 +398,6 @@ function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_leve
enchantments[selected_enchantment] = enchantment_power enchantments[selected_enchantment] = enchantment_power
mcl_enchanting.enchant(itemstack, selected_enchantment, enchantment_power) mcl_enchanting.enchant(itemstack, selected_enchantment, enchantment_power)
end end
until not no_reduced_bonus_chance and mcl_enchanting.random(pr) >= (enchantment_level + 1) / 50 until not no_reduced_bonus_chance and mcl_enchanting.random(pr) >= (enchantment_level + 1) / 50
return enchantments, description return enchantments, description
@ -397,13 +407,15 @@ function mcl_enchanting.generate_random_enchantments_reliable(itemstack, enchant
local enchantments local enchantments
repeat repeat
enchantments = mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr) enchantments = mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure,
no_reduced_bonus_chance, ignore_already_enchanted, pr)
until enchantments until enchantments
return enchantments return enchantments
end end
function mcl_enchanting.enchant_randomly(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr) function mcl_enchanting.enchant_randomly(itemstack, enchantment_level, treasure, no_reduced_bonus_chance,
ignore_already_enchanted, pr)
local enchantments = mcl_enchanting.generate_random_enchantments_reliable(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr) local enchantments = mcl_enchanting.generate_random_enchantments_reliable(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr)
mcl_enchanting.set_enchanted_itemstring(itemstack) mcl_enchanting.set_enchanted_itemstring(itemstack)
@ -416,7 +428,8 @@ function mcl_enchanting.enchant_uniform_randomly(stack, exclude, pr)
local enchantment = mcl_enchanting.get_random_enchantment(stack, true, false, exclude, pr) local enchantment = mcl_enchanting.get_random_enchantment(stack, true, false, exclude, pr)
if enchantment then if enchantment then
mcl_enchanting.enchant(stack, enchantment, mcl_enchanting.random(pr, 1, mcl_enchanting.enchantments[enchantment].max_level)) mcl_enchanting.enchant(stack, enchantment,
mcl_enchanting.random(pr, 1, mcl_enchanting.enchantments[enchantment].max_level))
end end
return stack return stack
@ -426,7 +439,8 @@ function mcl_enchanting.get_random_glyph_row()
local glyphs = "" local glyphs = ""
local x = 1.3 local x = 1.3
for i = 1, 9 do for i = 1, 9 do
glyphs = glyphs .. "image[".. x .. ",0.1;0.5,0.5;mcl_enchanting_glyph_" .. math.random(18) .. ".png^[colorize:#675D49:255]" glyphs = glyphs ..
"image[" .. x .. ",0.1;0.5,0.5;mcl_enchanting_glyph_" .. math.random(18) .. ".png^[colorize:#675D49:255]"
x = x + 0.6 x = x + 0.6
end end
return glyphs return glyphs
@ -491,28 +505,33 @@ function mcl_enchanting.show_enchanting_formspec(player)
local inv = player:get_inventory() local inv = player:get_inventory()
local num_bookshelves = meta:get_int("mcl_enchanting:num_bookshelves") local num_bookshelves = meta:get_int("mcl_enchanting:num_bookshelves")
local table_name = meta:get_string("mcl_enchanting:table_name") local table_name = meta:get_string("mcl_enchanting:table_name")
local formspec = ""
.. "size[9.07,8.6;]" local formspec = table.concat({
.. "formspec_version[3]" "formspec_version[4]",
.. "label[0,0;" .. C("#313131") .. F(table_name) .. "]" "size[11.75,10.425]",
.. mcl_formspec.get_itemslot_bg(0.2, 2.4, 1, 1)
.. "list[current_player;enchanting_item;0.2,2.4;1,1]" "label[0.375,0.375;" .. F(C(mcl_formspec.label_color) .. table_name) .. "]",
.. mcl_formspec.get_itemslot_bg(1.1, 2.4, 1, 1) mcl_formspec.get_itemslot_bg_v4(1, 3.25, 1, 1),
.. "image[1.1,2.4;1,1;mcl_enchanting_lapis_background.png]" "list[current_player;enchanting_item;1,3.25;1,1]",
.. "list[current_player;enchanting_lapis;1.1,2.4;1,1]" mcl_formspec.get_itemslot_bg_v4(2.25, 3.25, 1, 1),
.. "label[0,4;" .. C("#313131") .. F(S("Inventory")).."]" "image[2.25,3.25;1,1;mcl_enchanting_lapis_background.png]",
.. mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3) "list[current_player;enchanting_lapis;2.25,3.25;1,1]",
.. mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1) "image[4.125,0.56;7.25,4.1;mcl_enchanting_button_background.png]",
.. "list[current_player;main;0,4.5;9,3;9]" "label[0.375,4.7;" .. F(C(mcl_formspec.label_color) .. S("Inventory")) .. "]",
.. "listring[current_player;enchanting_item]" mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
.. "listring[current_player;main]" "list[current_player;main;0.375,5.1;9,3;9]",
.. "listring[current_player;enchanting]"
.. "listring[current_player;main]" mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
.. "listring[current_player;enchanting_lapis]" "list[current_player;main;0.375,9.05;9,1;]",
.. "listring[current_player;main]"
.. "list[current_player;main;0,7.74;9,1;]" "listring[current_player;enchanting_item]",
.. "real_coordinates[true]" "listring[current_player;main]",
.. "image[3.15,0.6;7.6,4.1;mcl_enchanting_button_background.png]" "listring[current_player;enchanting]",
"listring[current_player;main]",
"listring[current_player;enchanting_lapis]",
"listring[current_player;main]",
})
local itemstack = inv:get_stack("enchanting_item", 1) local itemstack = inv:get_stack("enchanting_item", 1)
local player_levels = mcl_experience.get_level(player) local player_levels = mcl_experience.get_level(player)
local y = 0.65 local y = 0.65
@ -526,18 +545,44 @@ function mcl_enchanting.show_enchanting_formspec(player)
local ending = (can_enchant and "" or "_off") local ending = (can_enchant and "" or "_off")
local hover_ending = (can_enchant and "_hovered" or "_off") local hover_ending = (can_enchant and "_hovered" or "_off")
formspec = formspec formspec = formspec
.. "container[3.2," .. y .. "]" .. "container[4.125," .. y .. "]"
.. (slot and "tooltip[button_" .. i .. ";" .. C("#818181") .. ((slot.description and F(slot.description)) or "") .. " " .. C("#FFFFFF") .. " . . . ?\n\n" .. (enough_levels and C(enough_lapis and "#818181" or "#FC5454") .. F(S("@1 Lapis Lazuli", i)) .. "\n" .. C("#818181") .. F(S("@1 Enchantment Levels", i)) or C("#FC5454") .. F(S("Level requirement: @1", slot.level_requirement))) .. "]" or "") ..
.. "style[button_" .. i .. ";bgimg=mcl_enchanting_button" .. ending .. ".png;bgimg_hovered=mcl_enchanting_button" .. hover_ending .. ".png;bgimg_pressed=mcl_enchanting_button" .. hover_ending .. ".png]" (
.. "button[0,0;7.5,1.3;button_" .. i .. ";]" slot and
"tooltip[button_" ..
i ..
";" ..
C("#818181") ..
((slot.description and F(slot.description)) or "") ..
" " ..
C("#FFFFFF") ..
" . . . ?\n\n" ..
(
enough_levels and
C(enough_lapis and "#818181" or "#FC5454") ..
F(S("@1 Lapis Lazuli", i)) .. "\n" .. C("#818181") .. F(S("@1 Enchantment Levels", i)) or
C("#FC5454") .. F(S("Level requirement: @1", slot.level_requirement))) .. "]" or "")
..
"style[button_" ..
i ..
";bgimg=mcl_enchanting_button" ..
ending ..
".png;bgimg_hovered=mcl_enchanting_button" ..
hover_ending .. ".png;bgimg_pressed=mcl_enchanting_button" .. hover_ending .. ".png]"
.. "button[0,0;7.25,1.3;button_" .. i .. ";]"
.. (slot and "image[0,0;1.3,1.3;mcl_enchanting_number_" .. i .. ending .. ".png]" or "") .. (slot and "image[0,0;1.3,1.3;mcl_enchanting_number_" .. i .. ending .. ".png]" or "")
.. (slot and "label[7.2,1.1;" .. C(can_enchant and "#80FF20" or "#407F10") .. slot.level_requirement .. "]" or "") .. (slot and "label[6.8,1;" .. C(can_enchant and "#80FF20" or "#407F10") .. slot.level_requirement .. "]" or "")
.. (slot and slot.glyphs or "") .. (slot and slot.glyphs or "")
.. "container_end[]" .. "container_end[]"
y = y + 1.35 y = y + 1.3
end end
formspec = formspec formspec = formspec
.. "image[" .. (any_enchantment and 0.58 or 1.15) .. ",1.2;" .. (any_enchantment and 2 or 0.87) .. ",1.43;mcl_enchanting_book_" .. (any_enchantment and "open" or "closed") .. ".png]" ..
"image[" ..
(any_enchantment and 1.1 or 1.67) ..
",1.2;" ..
(any_enchantment and 2 or 0.87) ..
",1.43;mcl_enchanting_book_" .. (any_enchantment and "open" or "closed") .. ".png]"
minetest.show_formspec(name, "mcl_enchanting:table", formspec) minetest.show_formspec(name, "mcl_enchanting:table", formspec)
end end
@ -603,7 +648,8 @@ function mcl_enchanting.is_enchanting_inventory_action(action, inventory, invent
end end
function mcl_enchanting.allow_inventory_action(player, action, inventory, inventory_info) function mcl_enchanting.allow_inventory_action(player, action, inventory, inventory_info)
local is_enchanting_action, do_limit = mcl_enchanting.is_enchanting_inventory_action(action, inventory, inventory_info) local is_enchanting_action, do_limit = mcl_enchanting.is_enchanting_inventory_action(action, inventory,
inventory_info)
if is_enchanting_action and do_limit then if is_enchanting_action and do_limit then
if action == "move" then if action == "move" then
local listname = inventory_info.to_list local listname = inventory_info.to_list
@ -650,8 +696,10 @@ end
function mcl_enchanting.set_book_animation(self, anim) function mcl_enchanting.set_book_animation(self, anim)
local anim_index = mcl_enchanting.book_animations[anim] local anim_index = mcl_enchanting.book_animations[anim]
local start, stop = mcl_enchanting.book_animation_steps[anim_index], mcl_enchanting.book_animation_steps[anim_index + 1] local start, stop = mcl_enchanting.book_animation_steps[anim_index],
self.object:set_animation({x = start, y = stop}, mcl_enchanting.book_animation_speed, 0, mcl_enchanting.book_animation_loop[anim] or false) mcl_enchanting.book_animation_steps[anim_index + 1]
self.object:set_animation({ x = start, y = stop }, mcl_enchanting.book_animation_speed, 0,
mcl_enchanting.book_animation_loop[anim] or false)
self.scheduled_anim = nil self.scheduled_anim = nil
self.anim_length = (stop - start) / 40 self.anim_length = (stop - start) / 40
end end

View file

@ -1,5 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local C = minetest.colorize
local F = minetest.formspec_escape
local LIGHT_ACTIVE_FURNACE = 13 local LIGHT_ACTIVE_FURNACE = 13
@ -8,60 +9,82 @@ local LIGHT_ACTIVE_FURNACE = 13
-- --
local function active_formspec(fuel_percent, item_percent) local function active_formspec(fuel_percent, item_percent)
return "size[9,8.75]".. return table.concat({
"label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "formspec_version[4]",
"list[current_player;main;0,4.5;9,3;9]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Furnace"))) .. "]",
"list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. "list[context;src;3.5,0.75;1,1;]",
"label[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Furnace"))).."]"..
"list[context;src;2.75,0.5;1,1;]".. "image[3.5,2;1,1;default_furnace_fire_bg.png^[lowpart:" ..
mcl_formspec.get_itemslot_bg(2.75,0.5,1,1).. (100 - fuel_percent) .. ":default_furnace_fire_fg.png]",
"list[context;fuel;2.75,2.5;1,1;]"..
mcl_formspec.get_itemslot_bg(2.75,2.5,1,1).. mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;dst;5.75,1.5;1,1;]".. "list[context;fuel;3.5,3.25;1,1;]",
mcl_formspec.get_itemslot_bg(5.75,1.5,1,1)..
"image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:".. "image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[lowpart:" ..
(100-fuel_percent)..":default_furnace_fire_fg.png]".. (item_percent) .. ":gui_furnace_arrow_fg.png^[transformR270]",
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[lowpart:".. mcl_formspec.get_itemslot_bg_v4(7.875, 2, 1, 1, 0.2),
(item_percent)..":gui_furnace_arrow_fg.png^[transformR270]".. "list[context;dst;7.875,2;1,1;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
-- Craft guide button temporarily removed due to Minetest bug. -- Craft guide button temporarily removed due to Minetest bug.
-- TODO: Add it back when the Minetest bug is fixed. -- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]".. --"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]".. --"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]".. "listring[context;dst]",
"listring[context;src]".. "listring[current_player;main]",
"listring[current_player;main]".. "listring[context;src]",
"listring[context;fuel]".. "listring[current_player;main]",
"listring[current_player;main]" "listring[context;fuel]",
"listring[current_player;main]",
})
end end
local inactive_formspec = "size[9,8.75]".. local inactive_formspec = table.concat({
"label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "formspec_version[4]",
"list[current_player;main;0,4.5;9,3;9]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Furnace"))) .. "]",
"list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. "list[context;src;3.5,0.75;1,1;]",
"label[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Furnace"))).."]"..
"list[context;src;2.75,0.5;1,1;]".. "image[3.5,2;1,1;default_furnace_fire_bg.png]",
mcl_formspec.get_itemslot_bg(2.75,0.5,1,1)..
"list[context;fuel;2.75,2.5;1,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
mcl_formspec.get_itemslot_bg(2.75,2.5,1,1).. "list[context;fuel;3.5,3.25;1,1;]",
"list[context;dst;5.75,1.5;1,1;]"..
mcl_formspec.get_itemslot_bg(5.75,1.5,1,1).. "image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[transformR270]",
"image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[transformR270]".. mcl_formspec.get_itemslot_bg_v4(7.875, 2, 1, 1, 0.2),
"list[context;dst;7.875,2;1,1;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
-- Craft guide button temporarily removed due to Minetest bug. -- Craft guide button temporarily removed due to Minetest bug.
-- TODO: Add it back when the Minetest bug is fixed. -- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]".. --"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]".. --"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]".. "listring[context;dst]",
"listring[context;src]".. "listring[current_player;main]",
"listring[current_player;main]".. "listring[context;src]",
"listring[context;fuel]".. "listring[current_player;main]",
"listring[current_player;main]" "listring[context;fuel]",
"listring[current_player;main]",
})
local receive_fields = function(pos, formname, fields, sender) local receive_fields = function(pos, formname, fields, sender)
if fields.craftguide then if fields.craftguide then
@ -465,7 +488,8 @@ minetest.register_node("mcl_furnaces:furnace", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1) local stack = inv:get_stack(listname, 1)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} local p = { x = pos.x + math.random(0, 10) / 10 - 0.5, y = pos.y,
z = pos.z + math.random(0, 10) / 10 - 0.5 }
minetest.add_item(p, stack) minetest.add_item(p, stack)
end end
end end
@ -541,7 +565,8 @@ minetest.register_node("mcl_furnaces:furnace_active", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1) local stack = inv:get_stack(listname, 1)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} local p = { x = pos.x + math.random(0, 10) / 10 - 0.5, y = pos.y,
z = pos.z + math.random(0, 10) / 10 - 0.5 }
minetest.add_item(p, stack) minetest.add_item(p, stack)
end end
end end

View file

@ -1,31 +1,46 @@
-- Code based from mcl_anvils -- Code based from mcl_anvils
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
local MAX_WEAR = 65535 local MAX_WEAR = 65535
-- formspecs local grindstone_formspec = table.concat({
local function get_grindstone_formspec() "formspec_version[6]",
return "size[9,8.75]".. "size[11.75,10.425]",
"image[3,1.5;1.5,1;gui_crafting_arrow.png]"..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Repair & Disenchant"))) .. "]",
"label[1,0.1;"..minetest.formspec_escape(minetest.colorize("#313131", S("Repair & Disenchant"))).."]"..
"list[context;main;0,0;8,4;]".. mcl_formspec.get_itemslot_bg_v4(2.875, 1.25, 1, 1),
"list[current_player;main;0,4.5;9,3;9]".. "list[context;input;2.875,1.25;1,1;]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
"list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg_v4(2.875, 2.625, 1, 1),
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. "list[context;input;2.875,2.625;1,1;1]",
"list[context;input;1,1;1,1;]"..
mcl_formspec.get_itemslot_bg(1,1,1,1).. "image[2.375,1;2,2.875;grindstone_gui_9.png;2]",
"list[context;input;1,2;1,1;1]"..
mcl_formspec.get_itemslot_bg(1,2,1,1).. "image[1.875,1.5;0.5,2.875;grindstone_gui_9.png;2]",
"list[context;output;6,1.5;1,1;]".. "image[4.375,1.5;0.5,2.875;grindstone_gui_9.png;2]",
mcl_formspec.get_itemslot_bg(6,1.5,1,1)..
"listring[context;output]".. "image[5.5,1.95;1.5,1;gui_crafting_arrow.png]",
"listring[current_player;main]"..
"listring[context;input]".. mcl_formspec.get_itemslot_bg_v4(7.875, 1.9375, 1, 1),
"listring[current_player;main]" "list[context;output;7.875,1.9375;1,1;]",
end
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[context;output]",
"listring[current_player;main]",
"listring[context;input]",
"listring[current_player;main]",
})
-- Creates a new item with the wear of the items and custom name -- Creates a new item with the wear of the items and custom name
local function create_new_item(name_item, meta, wear) local function create_new_item(name_item, meta, wear)
@ -86,7 +101,6 @@ local function fix_stack_size(stack)
return count return count
end end
-- Update the inventory slots of an grindstone node. -- Update the inventory slots of an grindstone node.
-- meta: Metadata of grindstone node -- meta: Metadata of grindstone node
local function update_grindstone_slots(meta) local function update_grindstone_slots(meta)
@ -289,8 +303,8 @@ minetest.register_node("mcl_grindstone:grindstone", {
if not input1:is_empty() and not input2:is_empty() then if not input1:is_empty() and not input2:is_empty() then
-- Get xp earnt from the enchanted items -- Get xp earnt from the enchanted items
xp_earnt = calculate_xp(input1) + calculate_xp(input1) xp_earnt = calculate_xp(input1) + calculate_xp(input1)
input1:take_item() input1:take_item(1)
input2:take_item() input2:take_item(1)
inv:set_stack("input", 1, input1) inv:set_stack("input", 1, input1)
inv:set_stack("input", 2, input2) inv:set_stack("input", 2, input2)
else else
@ -320,14 +334,13 @@ minetest.register_node("mcl_grindstone:grindstone", {
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size("input", 2) inv:set_size("input", 2)
inv:set_size("output", 1) inv:set_size("output", 1)
local form = get_grindstone_formspec() meta:set_string("formspec", grindstone_formspec)
meta:set_string("formspec", form)
end, end,
on_rightclick = function(pos, node, player, itemstack) on_rightclick = function(pos, node, player, itemstack)
if not player:get_player_control().sneak then if not player:get_player_control().sneak then
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
update_grindstone_slots(meta) update_grindstone_slots(meta)
meta:set_string("formspec", get_grindstone_formspec()) meta:set_string("formspec", grindstone_formspec)
end end
end, end,
_mcl_blast_resistance = 6, _mcl_blast_resistance = 6,

View file

@ -12,15 +12,22 @@ end
--[[ BEGIN OF NODE DEFINITIONS ]] --[[ BEGIN OF NODE DEFINITIONS ]]
local mcl_hoppers_formspec = table.concat({ local mcl_hoppers_formspec = table.concat({
"size[9,7]", "formspec_version[4]",
"label[2,0;" .. F(C("#313131", S("Hopper"))) .. "]", "size[11.75,8.175]",
"list[context;main;2,0.5;5,1;]",
mcl_formspec.get_itemslot_bg(2, 0.5, 5, 1), "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Hopper"))) .. "]",
"label[0,2;" .. F(C("#313131", S("Inventory"))) .. "]",
"list[current_player;main;0,2.5;9,3;9]", mcl_formspec.get_itemslot_bg_v4(2.875, 0.75, 5, 1),
mcl_formspec.get_itemslot_bg(0, 2.5, 9, 3), "list[context;main;2.875,0.75;5,1;]",
"list[current_player;main;0,5.74;9,1;]",
mcl_formspec.get_itemslot_bg(0, 5.74, 9, 1), "label[0.375,2.45;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 2.85, 9, 3),
"list[current_player;main;0.375,2.85;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 6.8, 9, 1),
"list[current_player;main;0.375,6.8;9,1;]",
"listring[context;main]", "listring[context;main]",
"listring[current_player;main]", "listring[current_player;main]",
}) })

View file

@ -1,11 +1,13 @@
--[[ -- By EliasFleckenstein03 and Code-Sploit
By EliasFleckenstein03 and Code-Sploit
]]
local S = minetest.get_translator("mcl_smithing_table") local S = minetest.get_translator("mcl_smithing_table")
local F = minetest.formspec_escape
local C = minetest.colorize
mcl_smithing_table = {} mcl_smithing_table = {}
-- Function to upgrade diamond tool/armor to netherite tool/armor ---Function to upgrade diamond tool/armor to netherite tool/armor
---@param itemstack ItemStack
function mcl_smithing_table.upgrade_item(itemstack) function mcl_smithing_table.upgrade_item(itemstack)
local def = itemstack:get_definition() local def = itemstack:get_definition()
@ -29,28 +31,48 @@ function mcl_smithing_table.upgrade_item(itemstack)
return itemstack return itemstack
end end
-- Badly copied over from mcl_anvils local formspec = table.concat({
-- ToDo: Make better formspec "formspec_version[4]",
"size[11.75,10.425]",
local formspec = "size[9,9]" .. "label[4.125,0.375;" .. F(C(mcl_formspec.label_color, S("Upgrade Gear"))) .. "]",
"background[-0.19,-0.25;9.41,9.49;mcl_smithing_table_inventory.png]"..
"label[0,4.0;" .. minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))) .. "]" ..
"list[current_player;main;0,4.5;9,3;9]" ..
mcl_formspec.get_itemslot_bg(0,4.5,9,3) ..
"list[current_player;main;0,7.74;9,1;]" ..
mcl_formspec.get_itemslot_bg(0,7.74,9,1) ..
"list[context;diamond_item;1,2.5;1,1;]" ..
mcl_formspec.get_itemslot_bg(1,2.5,1,1) ..
"list[context;netherite;4,2.5;1,1;]" ..
mcl_formspec.get_itemslot_bg(4,2.5,1,1) ..
"list[context;upgraded_item;8,2.5;1,1;]" ..
mcl_formspec.get_itemslot_bg(8,2.5,1,1) ..
"label[3,0.1;" .. minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Upgrade Gear"))) .. "]" ..
"listring[context;output]"..
"listring[current_player;main]"..
"listring[context;input]"..
"listring[current_player;main]"
"image[0.875,0.375;1.75,1.75;mcl_smithing_table_inventory_hammer.png]",
mcl_formspec.get_itemslot_bg_v4(1.625, 2.6, 1, 1),
"list[context;diamond_item;1.625,2.6;1,1;]",
"image[3.5,2.6;1,1;mcl_anvils_inventory_cross.png]",
mcl_formspec.get_itemslot_bg_v4(5.375, 2.6, 1, 1),
"list[context;netherite;5.375,2.6;1,1;]",
"image[6.75,2.6;2,1;mcl_anvils_inventory_arrow.png]",
mcl_formspec.get_itemslot_bg_v4(9.125, 2.6, 1, 1),
"list[context;upgraded_item;9.125,2.6;1,1;]",
-- Player Inventory
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
-- Listrings
"listring[context;diamond_item]",
"listring[current_player;main]",
"listring[context;netherite]",
"listring[current_player;main]",
"listring[context;upgraded_item]",
"listring[current_player;main]",
"listring[current_player;main]",
"listring[context;diamond_item]",
})
---@param pos Vector
local function reset_upgraded_item(pos) local function reset_upgraded_item(pos)
local inv = minetest.get_meta(pos):get_inventory() local inv = minetest.get_meta(pos):get_inventory()
local upgraded_item local upgraded_item
@ -66,7 +88,6 @@ minetest.register_node("mcl_smithing_table:table", {
description = S("Smithing table"), description = S("Smithing table"),
-- ToDo: Add _doc_items_longdesc and _doc_items_usagehelp -- ToDo: Add _doc_items_longdesc and _doc_items_usagehelp
stack_max = 64,
groups = { pickaxey = 2, deco_block = 1 }, groups = { pickaxey = 2, deco_block = 1 },
tiles = { tiles = {
@ -92,7 +113,8 @@ minetest.register_node("mcl_smithing_table:table", {
end, end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player) allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname == "diamond_item" and mcl_smithing_table.upgrade_item(stack) or listname == "netherite" and stack:get_name() == "mcl_nether:netherite_ingot" then if listname == "diamond_item" and mcl_smithing_table.upgrade_item(stack) or
listname == "netherite" and stack:get_name() == "mcl_nether:netherite_ingot" then
return stack:get_count() return stack:get_count()
end end
@ -141,5 +163,5 @@ minetest.register_craft({
{ "mcl_core:iron_ingot", "mcl_core:iron_ingot", "" }, { "mcl_core:iron_ingot", "mcl_core:iron_ingot", "" },
{ "group:wood", "group:wood", "" }, { "group:wood", "group:wood", "" },
{ "group:wood", "group:wood", "" } { "group:wood", "group:wood", "" }
} },
}) })

View file

@ -1,2 +1,2 @@
name = mcl_smithing_table name = mcl_smithing_table
depends = mcl_colors, mcl_formspec depends = mcl_colors, mcl_formspec, mcl_anvils

View file

@ -1,5 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local C = minetest.colorize
local F = minetest.formspec_escape
local LIGHT_ACTIVE_FURNACE = 13 local LIGHT_ACTIVE_FURNACE = 13
@ -8,60 +9,82 @@ local LIGHT_ACTIVE_FURNACE = 13
-- --
local function active_formspec(fuel_percent, item_percent) local function active_formspec(fuel_percent, item_percent)
return "size[9,8.75]".. return table.concat({
"label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "formspec_version[4]",
"list[current_player;main;0,4.5;9,3;9]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Smoker"))) .. "]",
"list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. "list[context;src;3.5,0.75;1,1;]",
"label[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Smoker"))).."]"..
"list[context;src;2.75,0.5;1,1;]".. "image[3.5,2;1,1;default_furnace_fire_bg.png^[lowpart:" ..
mcl_formspec.get_itemslot_bg(2.75,0.5,1,1).. (100 - fuel_percent) .. ":default_furnace_fire_fg.png]",
"list[context;fuel;2.75,2.5;1,1;]"..
mcl_formspec.get_itemslot_bg(2.75,2.5,1,1).. mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;dst;5.75,1.5;1,1;]".. "list[context;fuel;3.5,3.25;1,1;]",
mcl_formspec.get_itemslot_bg(5.75,1.5,1,1)..
"image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:".. "image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[lowpart:" ..
(100-fuel_percent)..":default_furnace_fire_fg.png]".. (item_percent) .. ":gui_furnace_arrow_fg.png^[transformR270]",
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[lowpart:".. mcl_formspec.get_itemslot_bg_v4(7.875, 2, 1, 1, 0.2),
(item_percent)..":gui_furnace_arrow_fg.png^[transformR270]".. "list[context;dst;7.875,2;1,1;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
-- Craft guide button temporarily removed due to Minetest bug. -- Craft guide button temporarily removed due to Minetest bug.
-- TODO: Add it back when the Minetest bug is fixed. -- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]".. --"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]".. --"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]".. "listring[context;dst]",
"listring[context;src]".. "listring[current_player;main]",
"listring[current_player;main]".. "listring[context;src]",
"listring[context;fuel]".. "listring[current_player;main]",
"listring[current_player;main]" "listring[context;fuel]",
"listring[current_player;main]",
})
end end
local inactive_formspec = "size[9,8.75]".. local inactive_formspec = table.concat({
"label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. "formspec_version[4]",
"list[current_player;main;0,4.5;9,3;9]".. "size[11.75,10.425]",
mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Smoker"))) .. "]",
"list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
mcl_formspec.get_itemslot_bg(0,7.74,9,1).. "list[context;src;3.5,0.75;1,1;]",
"label[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Smoker"))).."]"..
"list[context;src;2.75,0.5;1,1;]".. "image[3.5,2;1,1;default_furnace_fire_bg.png]",
mcl_formspec.get_itemslot_bg(2.75,0.5,1,1)..
"list[context;fuel;2.75,2.5;1,1;]".. mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
mcl_formspec.get_itemslot_bg(2.75,2.5,1,1).. "list[context;fuel;3.5,3.25;1,1;]",
"list[context;dst;5.75,1.5;1,1;]"..
mcl_formspec.get_itemslot_bg(5.75,1.5,1,1).. "image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[transformR270]",
"image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[transformR270]".. mcl_formspec.get_itemslot_bg_v4(7.875, 2, 1, 1, 0.2),
"list[context;dst;7.875,2;1,1;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
-- Craft guide button temporarily removed due to Minetest bug. -- Craft guide button temporarily removed due to Minetest bug.
-- TODO: Add it back when the Minetest bug is fixed. -- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]".. --"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]".. --"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]".. "listring[context;dst]",
"listring[context;src]".. "listring[current_player;main]",
"listring[current_player;main]".. "listring[context;src]",
"listring[context;fuel]".. "listring[current_player;main]",
"listring[current_player;main]" "listring[context;fuel]",
"listring[current_player;main]",
})
local receive_fields = function(pos, formname, fields, sender) local receive_fields = function(pos, formname, fields, sender)
if fields.craftguide then if fields.craftguide then
@ -415,7 +438,8 @@ end
minetest.register_node("mcl_smoker:smoker", { minetest.register_node("mcl_smoker:smoker", {
description = S("Smoker"), description = S("Smoker"),
_tt_help = S("Cooks food faster than furnace"), _tt_help = S("Cooks food faster than furnace"),
_doc_items_longdesc = S("Smokers cook several items, mainly raw foods, into cooked foods, but twice as fast as a normal furnace."), _doc_items_longdesc = S(
"Smokers cook several items, mainly raw foods, into cooked foods, but twice as fast as a normal furnace."),
_doc_items_usagehelp = _doc_items_usagehelp =
S("Use the smoker to open the furnace menu.") .. "\n" .. S("Use the smoker to open the furnace menu.") .. "\n" ..
S("Place a furnace fuel in the lower slot and the source material in the upper slot.") .. "\n" .. S("Place a furnace fuel in the lower slot and the source material in the upper slot.") .. "\n" ..
@ -442,7 +466,11 @@ minetest.register_node("mcl_smoker:smoker", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1) local stack = inv:get_stack(listname, 1)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} local p = {
x = pos.x + math.random(0, 10) / 10 - 0.5,
y = pos.y,
z = pos.z + math.random(0, 10) / 10 - 0.5
}
minetest.add_item(p, stack) minetest.add_item(p, stack)
end end
end end
@ -499,8 +527,10 @@ minetest.register_node("mcl_smoker:smoker_active", {
tiles = { tiles = {
"smoker_top.png", "smoker_bottom.png", "smoker_top.png", "smoker_bottom.png",
"smoker_side.png", "smoker_side.png", "smoker_side.png", "smoker_side.png",
"smoker_side.png", {name = "smoker_front_on.png", "smoker_side.png", {
animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 48}}, name = "smoker_front_on.png",
animation = { type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 48 }
},
}, },
paramtype2 = "facedir", paramtype2 = "facedir",
paramtype = "light", paramtype = "light",
@ -519,7 +549,11 @@ minetest.register_node("mcl_smoker:smoker_active", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1) local stack = inv:get_stack(listname, 1)
if not stack:is_empty() then if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} local p = {
x = pos.x + math.random(0, 10) / 10 - 0.5,
y = pos.y,
z = pos.z + math.random(0, 10) / 10 - 0.5
}
minetest.add_item(p, stack) minetest.add_item(p, stack)
end end
end end

View file

@ -0,0 +1,27 @@
# `mcl_gamemode`
## `mcl_gamemode.gamemodes`
List of availlable gamemodes.
Currently `{"survival", "creative"}`
## `mcl_gamemode.get_gamemode(player)`
Get the player's gamemode.
Returns "survival" or "creative".
## `mcl_gamemode.set_gamemode(player, gamemode)`
Set the player's gamemode.
gamemode: "survival" or "creative"
## `mcl_gamemode.register_on_gamemode_change(function(player, old_gamemode, new_gamemode))`
Register a function that will be called when `mcl_gamemode.set_gamemode` is called.
## `mcl_gamemode.registered_on_gamemode_change`
Map of registered on_gamemode_change.

View file

@ -0,0 +1,84 @@
local S = minetest.get_translator("mcl_gamemode")
mcl_gamemode = {}
mcl_gamemode.gamemodes = {
"survival",
"creative",
}
---@param n any
---@param h table
---@return boolean
local function in_table(n, h)
for k, v in pairs(h) do
if v == n then return true end
end
return false
end
---@type fun(player: mt.PlayerObjectRef, old_gamemode: '"survival"'|'"creative"', new_gamemode: '"survival"'|'"creative"')[]
mcl_gamemode.registered_on_gamemode_change = {}
---@param func fun(player: mt.PlayerObjectRef, old_gamemode: '"survival"'|'"creative"', new_gamemode: '"survival"'|'"creative"')
function mcl_gamemode.register_on_gamemode_change(func)
table.insert(mcl_gamemode.registered_on_gamemode_change, func)
end
---@param player mt.PlayerObjectRef
---@param gamemode '"survival"'|'"creative"'
function mcl_gamemode.set_gamemode(player, gamemode)
local meta = player:get_meta()
local old_gamemode = meta:get_string("gamemode")
meta:set_string("gamemode", gamemode)
for _, f in ipairs(mcl_gamemode.registered_on_gamemode_change) do
f(player, old_gamemode, gamemode)
end
end
local mt_is_creative_enabled = minetest.is_creative_enabled
---@param player mt.PlayerObjectRef
---@return '"survival"'|'"creative"'
function mcl_gamemode.get_gamemode(player)
if mt_is_creative_enabled(player:get_player_name()) then
return "creative"
end
return player:get_meta():get_string("gamemode")
end
function minetest.is_creative_enabled(name)
if mt_is_creative_enabled(name) then return true end
if not name then return false end
local p = minetest.get_player_by_name(name)
if p then
return p:get_meta():get_string("gamemode") == "creative"
end
return false
end
minetest.register_chatcommand("gamemode", {
params = S("[<gamemode>] [<player>]"),
description = S("Change gamemode (survival/creative) for yourself or player"),
privs = { server = true },
func = function(n, param)
-- Full input validation ( just for @erlehmann <3 )
local p = minetest.get_player_by_name(n)
local args = param:split(" ")
if args[2] ~= nil then
p = minetest.get_player_by_name(args[2])
end
if not p then
return false, S("Player not online")
end
if args[1] ~= nil and not in_table(args[1], mcl_gamemode.gamemodes) then
return false, S("Gamemode " .. args[1] .. " does not exist.")
elseif args[1] ~= nil then
mcl_gamemode.set_gamemode(p, args[1])
end
--Result message - show effective game mode
local gm = p:get_meta():get_string("gamemode")
if gm == "" then gm = mcl_gamemode.gamemodes[1] end
return true, S("Gamemode for player ") .. n .. S(": " .. gm)
end
})

View file

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

View file

@ -89,6 +89,10 @@ minetest.register_on_joinplayer(function(player)
player:get_inventory():set_size("hand", 1) player:get_inventory():set_size("hand", 1)
end) end)
mcl_gamemode.register_on_gamemode_change(function(player)
mcl_meshhand.update_player(player)
end)
if mcl_skins_enabled then if mcl_skins_enabled then
mcl_player.register_on_visual_change(mcl_meshhand.update_player) mcl_player.register_on_visual_change(mcl_meshhand.update_player)
else else

View file

@ -1,5 +1,5 @@
name = mcl_meshhand name = mcl_meshhand
author = jordan4ibanez author = jordan4ibanez
description = Applies the player skin texture to the hand. description = Applies the player skin texture to the hand.
depends = mcl_tools, mcl_player depends = mcl_tools, mcl_player, mcl_gamemode
optional_depends = mcl_skins, mcl_custom_skins optional_depends = mcl_skins, mcl_custom_skins

View file

@ -1,3 +1,4 @@
local string = string
local sf = string.format local sf = string.format
-- Minetest 0.4 mod: player -- Minetest 0.4 mod: player
@ -11,7 +12,8 @@ local animation_blend = 0
local function get_mouse_button(player) local function get_mouse_button(player)
local controls = player:get_player_control() local controls = player:get_player_control()
local get_wielded_item_name = player:get_wielded_item():get_name() local get_wielded_item_name = player:get_wielded_item():get_name()
if controls.RMB and not string.find(get_wielded_item_name, "mcl_bows:bow") and not string.find(get_wielded_item_name, "mcl_bows:crossbow") and if controls.RMB and not string.find(get_wielded_item_name, "mcl_bows:bow") and
not string.find(get_wielded_item_name, "mcl_bows:crossbow") and
not mcl_shields.wielding_shield(player, 1) and not mcl_shields.wielding_shield(player, 2) or controls.LMB then not mcl_shields.wielding_shield(player, 1) and not mcl_shields.wielding_shield(player, 2) or controls.LMB then
return true return true
else else
@ -49,7 +51,7 @@ function mcl_player.player_get_animation(player)
model = player_model[name], model = player_model[name],
textures = textures, textures = textures,
animation = player_anim[name], animation = player_anim[name],
visibility = player_visibility[name] visibility = player_visible[name]
} }
end end
@ -133,6 +135,13 @@ function mcl_player.player_set_armor(player, texture)
update_player_textures(player) update_player_textures(player)
end end
---@param player mt.PlayerObjectRef
---@param x number
---@param y number
---@param w number
---@param h number
---@param fsname string
---@return string
function mcl_player.get_player_formspec_model(player, x, y, w, h, fsname) function mcl_player.get_player_formspec_model(player, x, y, w, h, fsname)
local name = player:get_player_name() local name = player:get_player_name()
local model = player_model[name] local model = player_model[name]
@ -166,6 +175,7 @@ minetest.register_on_joinplayer(function(player)
mcl_player.player_attached[name] = false mcl_player.player_attached[name] = false
player_visible[name] = true player_visible[name] = true
player_textures[name] = { "character.png", "blank.png", "blank.png" } player_textures[name] = { "character.png", "blank.png", "blank.png" }
--player:set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, 30) --player:set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, 30)
player:set_fov(86.1) -- see <https://minecraft.gamepedia.com/Options#Video_settings>>>> player:set_fov(86.1) -- see <https://minecraft.gamepedia.com/Options#Video_settings>>>>
end) end)
@ -225,7 +235,9 @@ minetest.register_globalstep(function(dtime)
or walking and velocity.z > 0.35 or walking and velocity.z > 0.35
or walking and velocity.z < -0.35 then or walking and velocity.z < -0.35 then
local wielded_itemname = player:get_wielded_item():get_name() local wielded_itemname = player:get_wielded_item():get_name()
local no_arm_moving = string.find(wielded_itemname, "mcl_bows:bow") or mcl_shields.wielding_shield(player, 1) or mcl_shields.wielding_shield(player, 2) local no_arm_moving = string.find(wielded_itemname, "mcl_bows:bow") or
mcl_shields.wielding_shield(player, 1) or
mcl_shields.wielding_shield(player, 2)
if player_sneak[name] ~= controls.sneak then if player_sneak[name] ~= controls.sneak then
player_anim[name] = nil player_anim[name] = nil
player_sneak[name] = controls.sneak player_sneak[name] = controls.sneak
@ -234,7 +246,8 @@ minetest.register_globalstep(function(dtime)
player_set_animation(player, "swim_walk_mine", animation_speed_mod) player_set_animation(player, "swim_walk_mine", animation_speed_mod)
elseif not controls.sneak and head_in_water and is_sprinting == true then elseif not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_walk", animation_speed_mod) player_set_animation(player, "swim_walk", animation_speed_mod)
elseif no_arm_moving and controls.RMB and controls.sneak or string.find(wielded_itemname, "mcl_bows:crossbow_") and controls.sneak then elseif no_arm_moving and controls.RMB and controls.sneak or
string.find(wielded_itemname, "mcl_bows:crossbow_") and controls.sneak then
player_set_animation(player, "bow_sneak", animation_speed_mod) player_set_animation(player, "bow_sneak", animation_speed_mod)
elseif no_arm_moving and controls.RMB or string.find(wielded_itemname, "mcl_bows:crossbow_") then elseif no_arm_moving and controls.RMB or string.find(wielded_itemname, "mcl_bows:crossbow_") then
player_set_animation(player, "bow_walk", animation_speed_mod) player_set_animation(player, "bow_walk", animation_speed_mod)

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 B

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 320 B