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>
AFCMS 2023-08-26 07:27:25 +00:00
commit f008fa3323
47 changed files with 2413 additions and 1397 deletions

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

22
.luarc.json Normal 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"]
}

@ -247,3 +247,12 @@ end)
minetest.register_on_mods_loaded(function()
table.sort(mcl_experience.on_add_xp, function(a, b) return a.priority < b.priority 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)

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

@ -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

@ -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)

@ -1,5 +1,13 @@
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)
local out = ""
for i = 0, w - 1, 1 do
@ -9,3 +17,40 @@ function mcl_formspec.get_itemslot_bg(x, y, w, h)
end
return out
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

@ -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,
```

@ -3,19 +3,35 @@ local F = minetest.formspec_escape
local C = minetest.colorize
-- Prepare player info table
---@type table<string, {page: string, filter: string, start_i: integer, inv_size: integer}>
local players = {}
-- Containing all the items for each Creative Mode tab
---@type table<string, string[]>
local inventory_lists = {}
--local mod_player = minetest.get_modpath("mcl_player")
-- 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
inventory_lists[f] = {}
end
---@param tbl string[]
local function replace_enchanted_books(tbl)
for k, item in ipairs(tbl) do
if item:find("mcl_enchanting:book_enchanted") == 1 then
@ -28,20 +44,32 @@ local function replace_enchanted_books(tbl)
end
end
--[[ Populate all the item tables. We only do this once. Note this code must be
executed after loading all the other mods in order to work. ]]
-- Populate all the item tables. We only do this once.
-- Note this code must be executed after loading all the other mods in order to work.
minetest.register_on_mods_loaded(function()
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)
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
---@param def mt.ItemDef|mt.NodeDef
local function is_tool(def)
return def.groups.tool or (def.tool_capabilities and def.tool_capabilities.damage_groups == nil)
end
---@param def mt.ItemDef|mt.NodeDef
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
-- Is set to true if it was added in any category besides misc
local nonmisc = false
if def.groups.building_block then
@ -110,6 +138,11 @@ minetest.register_on_mods_loaded(function()
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 desc
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)
end
---@param filter string
---@param player mt.PlayerObjectRef
local function set_inv_search(filter, player)
local playername = player:get_player_name()
local inv = minetest.get_inventory({ type = "detached", name = "creative_" .. playername })
local creative_list = {}
local lang = minetest.get_player_information(playername).lang_code
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
table.insert(creative_list, name)
end
@ -147,6 +183,8 @@ local function set_inv_search(filter, player)
inv:set_list("main", creative_list)
end
---@param page string
---@param player mt.PlayerObjectRef
local function set_inv_page(page, player)
local playername = player:get_player_name()
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)
end
---@param player mt.PlayerObjectRef
local function init(player)
local playername = player:get_player_name()
minetest.create_detached_inventory("creative_" .. playername, {
@ -197,24 +237,45 @@ local trash = minetest.create_detached_inventory("trash", {
inv:set_stack(listname, index, "")
end,
})
trash:set_size("main", 1)
local noffset = {} -- numeric tab offset
local offset = {} -- string offset:
local boffset = {} --
local hoch = {}
local filtername = {}
--local bg = {}
------------------------------
-- Formspec Precalculations --
------------------------------
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_y = -0.25
local noffset_y = -1.34
---@param id string
---@param right? boolean
local function next_noffset(id, right)
if right then
noffset[id] = { 8.94, noffset_y }
noffset[id] = { 11.3, noffset_y }
else
noffset[id] = { noffset_x, noffset_y }
noffset_x = noffset_x + 1.25
noffset_x = noffset_x + 1.6
end
end
@ -228,7 +289,7 @@ next_noffset("misc")
next_noffset("nix", true)
noffset_x = noffset_x_start
noffset_y = 8.12
noffset_y = 8.64
-- Lower row
next_noffset("food")
@ -240,23 +301,23 @@ next_noffset("inv", true)
for k, v in pairs(noffset) do
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
hoch["blocks"] = ""
hoch["deco"] = ""
hoch["redstone"] = ""
hoch["rail"] = ""
hoch["brew"] = ""
hoch["misc"] = ""
hoch["nix"] = ""
hoch["default"] = ""
hoch["food"] = "_down"
hoch["tools"] = "_down"
hoch["combat"] = "_down"
hoch["mobs"] = "_down"
hoch["matr"] = "_down"
hoch["inv"] = "_down"
button_bg_postfix["blocks"] = ""
button_bg_postfix["deco"] = ""
button_bg_postfix["redstone"] = ""
button_bg_postfix["rail"] = ""
button_bg_postfix["brew"] = ""
button_bg_postfix["misc"] = ""
button_bg_postfix["nix"] = ""
button_bg_postfix["default"] = ""
button_bg_postfix["food"] = "_down"
button_bg_postfix["tools"] = "_down"
button_bg_postfix["combat"] = "_down"
button_bg_postfix["mobs"] = "_down"
button_bg_postfix["matr"] = "_down"
button_bg_postfix["inv"] = "_down"
filtername["blocks"] = S("Building Blocks")
filtername["deco"] = S("Decoration Blocks")
@ -291,120 +352,8 @@ filtername["inv"] = S("Survival Inventory")
bg["default"] = dark_bg
end]]
local function get_stack_size(player)
return player:get_meta():get_int("mcl_inventory:switch_stack")
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
-- Item name representing a tab, indexed by tab name
---@type table<string, string>
local tab_icon = {
blocks = "mcl_core:brick_block",
deco = "mcl_flowers:peony",
@ -420,66 +369,233 @@ function mcl_inventory.set_creative_formspec(player)
matr = "mcl_core:stick",
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 bg_img
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
bg_img = "crafting_creative_inactive"..hoch[this_tab]..".png"
bg_img = "crafting_creative_inactive" .. button_bg_postfix[this_tab] .. ".png"
end
return
"style["..this_tab..";border=false;bgimg=;bgimg_pressed=]"..
"item_image_button[" .. boffset[this_tab] ..";1,1;"..tab_icon[this_tab]..";"..this_tab..";]"..
"image[" .. offset[this_tab] .. ";1.5,1.44;" .. bg_img .. "]"
return table.concat({
"style[" .. this_tab .. ";border=false;bgimg=;bgimg_pressed=;noclip=true]",
"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
local caption = ""
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
local formspec = "size[10,9.3]"..
"no_prepend[]"..
mcl_vars.gui_nonbg..mcl_vars.gui_bg_color..
"background[-0.19,-0.25;10.5,9.87;"..inv_bg.."]"..
"label[-5,-5;"..name.."]"..
tab(name, "blocks") ..
"tooltip[blocks;"..F(filtername["blocks"]).."]"..
tab(name, "deco") ..
"tooltip[deco;"..F(filtername["deco"]).."]"..
tab(name, "redstone") ..
"tooltip[redstone;"..F(filtername["redstone"]).."]"..
tab(name, "rail") ..
"tooltip[rail;"..F(filtername["rail"]).."]"..
tab(name, "misc") ..
"tooltip[misc;"..F(filtername["misc"]).."]"..
tab(name, "nix") ..
"tooltip[nix;"..F(filtername["nix"]).."]"..
caption..
"list[current_player;main;0,7;9,1;]"..
mcl_formspec.get_itemslot_bg(0,7,9,1)..
main_list..
tab(name, "food") ..
"tooltip[food;"..F(filtername["food"]).."]"..
tab(name, "tools") ..
"tooltip[tools;"..F(filtername["tools"]).."]"..
tab(name, "combat") ..
"tooltip[combat;"..F(filtername["combat"]).."]"..
tab(name, "mobs") ..
"tooltip[mobs;"..F(filtername["mobs"]).."]"..
tab(name, "brew") ..
"tooltip[brew;"..F(filtername["brew"]).."]"..
tab(name, "matr") ..
"tooltip[matr;"..F(filtername["matr"]).."]"..
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
local formspec = table.concat({
"formspec_version[6]",
"size[13,8.75]",
"style_type[image;noclip=true]",
-- Hotbar
mcl_formspec.get_itemslot_bg_v4(0.375, 7.375, 9, 1),
"list[current_player;main;0.375,7.375;9,1;]",
-- Trash
mcl_formspec.get_itemslot_bg_v4(11.625, 7.375, 1, 1, nil, "crafting_creative_trash.png"),
"list[detached:trash;main;11.625,7.375;1,1;]",
main_list,
caption,
listrings,
tab(name, "blocks"),
tab(name, "deco"),
tab(name, "redstone"),
tab(name, "rail"),
tab(name, "misc"),
tab(name, "nix"),
tab(name, "food"),
tab(name, "tools"),
tab(name, "combat"),
tab(name, "mobs"),
tab(name, "brew"),
tab(name, "matr"),
tab(name, "inv"),
})
if name == "nix" then
formspec = formspec .. "field[5.3,1.34;4,0.75;search;;"..minetest.formspec_escape(filter).."]"
formspec = formspec .. "field_close_on_enter[search;false]"
if filter == nil then
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
if pagenum then formspec = formspec .. "p" .. tostring(pagenum) end
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)
end)
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())
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)
-- Initialize variables and inventory
local name = player:get_player_name()
@ -629,7 +768,8 @@ minetest.register_on_joinplayer(function(player)
end)
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
stack:set_count(stack:get_stack_max())
player:get_inventory():set_stack("main", inventory_info.index, stack)

@ -1,13 +1,17 @@
local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
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_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
function return_item(itemstack, dropper, pos, inv)
---Returns a single itemstack in the given inventory to the main inventory, or drop it when there's no space left.
---@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
-- Return to main inventory
if inv:room_for_item("main", itemstack) then
@ -15,7 +19,7 @@ function return_item(itemstack, dropper, pos, inv)
else
-- Drop item on the ground
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.z = p.z + (math.random(1, 3) * 0.2)
local obj = minetest.add_item(p, itemstack)
@ -34,9 +38,12 @@ function return_item(itemstack, dropper, pos, inv)
return itemstack
end
-- 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)
---Return items in the given inventory list (name) to the main inventory, or drop them if there is no space left.
---@param player mt.PlayerObjectRef
---@param name string
local function return_fields(player, name)
local inv = player:get_inventory()
local list = inv:get_list(name)
if not list then return end
for i, stack in ipairs(list) do
@ -46,84 +53,20 @@ function return_fields(player, name)
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
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
end
local inv = player:get_inventory()
inv:set_width("craft", 2)
inv:set_size("craft", 4)
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,"..(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)
player:set_inventory_formspec(mcl_inventory.build_survival_formspec(player))
end
-- 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)
mcl_inventory.update_inventory_formspec = set_inventory
function mcl_inventory.update_inventory_formspec(player)
set_inventory(player)
end
-- Drop crafting grid items on leaving
minetest.register_on_leaveplayer(function(player)
@ -150,6 +96,7 @@ end)
minetest.register_on_joinplayer(function(player)
--init inventory
local inv = player:get_inventory()
inv:set_width("main", 9)
inv:set_size("main", 36)
inv:set_size("offhand", 1)
@ -174,73 +121,18 @@ minetest.register_on_joinplayer(function(player)
return_fields(player, "enchanting_lapis")
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)
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
})

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

@ -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)

@ -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.
]]
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)
-- 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)
meta:set_string("formspec", form)
meta:set_string("formspec", dispenser_formspec)
local inv = meta:get_inventory()
inv:set_size("main", 9)
end
@ -88,8 +101,7 @@ local dispenserdef = {
for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i)
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(p, stack)
minetest.add_item(vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5), stack)
end
end
meta:from_table(meta2)
@ -107,11 +119,11 @@ local dispenserdef = {
dropdir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
droppos = vector.add(pos, dropdir)
elseif node.name == "mcl_dispensers:dispenser_up" then
dropdir = {x=0, y=1, z=0}
droppos = {x=pos.x, y=pos.y+1, z=pos.z}
dropdir = vector.new(0, 1, 0)
droppos = vector.offset(pos, 0, 1, 0)
elseif node.name == "mcl_dispensers:dispenser_down" then
dropdir = {x=0, y=-1, z=0}
droppos = {x=pos.x, y=pos.y-1, z=pos.z}
dropdir = vector.new(0, -1, 0)
droppos = vector.offset(pos, 0, -1, 0)
end
local dropnode = minetest.get_node(droppos)
local dropnodedef = minetest.registered_nodes[dropnode.name]
@ -143,9 +155,10 @@ local dispenserdef = {
-- Armor, mob heads and pumpkins
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
stack = mcl_armor.equip(stack, obj)
if stack:is_empty() then
@ -301,7 +314,8 @@ local horizontal_def = table.copy(dispenserdef)
horizontal_def.description = S("Dispenser")
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_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" ..

@ -9,23 +9,36 @@ are so many weird tables below.
]]
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)
-- 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)
meta:set_string("formspec", form)
meta:set_string("formspec", dropper_formspec)
local inv = meta:get_inventory()
inv:set_size("main", 9)
end
@ -61,8 +74,7 @@ local dropperdef = {
for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i)
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(p, stack)
minetest.add_item(vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5), stack)
end
end
meta:from_table(meta2)
@ -106,9 +118,9 @@ local dropperdef = {
if node.name == "mcl_droppers:dropper" then
droppos = vector.subtract(pos, minetest.facedir_to_dir(node.param2))
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
droppos = {x=pos.x, y=pos.y-1, z=pos.z}
droppos = vector.offset(pos, 0, -1, 0)
end
local dropnode = minetest.get_node(droppos)
-- 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
-- Drop item normally
local pos_variation = 100
droppos = {
x = droppos.x + math.random(-pos_variation, pos_variation) / 1000,
y = droppos.y + math.random(-pos_variation, pos_variation) / 1000,
z = droppos.z + math.random(-pos_variation, pos_variation) / 1000,
}
droppos = vector.offset(droppos,
math.random(-pos_variation, pos_variation) / 1000,
math.random(-pos_variation, pos_variation) / 1000,
math.random(-pos_variation, pos_variation) / 1000
)
local item_entity = minetest.add_item(droppos, dropitem)
local drop_vel = vector.subtract(droppos, pos)
local speed = 3
@ -166,6 +178,7 @@ function horizontal_def.after_place_node(pos, placer, itemstack, pointed_thing)
setup_dropper(pos)
orientate_dropper(pos, placer)
end
horizontal_def.tiles = {
"default_furnace_top.png", "default_furnace_bottom.png",
"default_furnace_side.png", "default_furnace_side.png",

@ -1,4 +1,6 @@
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_WEAR = 65535
@ -10,35 +12,59 @@ local MATERIAL_TOOL_REPAIR_BOOST = {
MAX_WEAR, -- 100%
}
---@param set_name? string
local function get_anvil_formspec(set_name)
if not set_name then
set_name = ""
end
return "size[9,8.75]"..
"background[-0.19,-0.25;9.41,9.49;mcl_anvils_inventory.png]"..
"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)..
"list[context;input;1,2.5;1,1;]"..
mcl_formspec.get_itemslot_bg(1,2.5,1,1)..
"list[context;input;4,2.5;1,1;1]"..
mcl_formspec.get_itemslot_bg(4,2.5,1,1)..
"list[context;output;8,2.5;1,1;]"..
mcl_formspec.get_itemslot_bg(8,2.5,1,1)..
"label[3,0.1;"..minetest.formspec_escape(minetest.colorize("#313131", S("Repair and Name"))).."]"..
"field[3.25,1;4,1;name;;"..minetest.formspec_escape(set_name).."]"..
"field_close_on_enter[name;false]"..
"button[7,0.7;2,1;name_button;"..minetest.formspec_escape(S("Set Name")).."]"..
"listring[context;output]"..
"listring[current_player;main]"..
"listring[context;input]"..
"listring[current_player;main]"
return table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[4.125,0.375;" .. F(C(mcl_formspec.label_color, S("Repair and Name"))) .. "]",
"image[0.875,0.375;1.75,1.75;mcl_anvils_inventory_hammer.png]",
"field[4.125,0.75;7.25,1;name;;" .. F(set_name) .. "]",
"field_close_on_enter[name;false]",
"set_focus[name;true]",
mcl_formspec.get_itemslot_bg_v4(1.625, 2.6, 1, 1),
"list[context;input;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;input;5.375,2.6;1,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;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
-- Given a tool and material stack, returns how many items of the material stack
-- 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 wear = tool:get_wear()
--local health = (MAX_WEAR - wear)
@ -53,27 +79,20 @@ local function get_consumed_materials(tool, material)
return materials_used
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.
-- 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 nil otherwise.
---@param input1 ItemStack
---@param input2 ItemStack
local function distinguish_tool_and_material(input1, input2)
local def1 = input1:get_definition()
local def2 = input2:get_definition()
local r1 = def1._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
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
elseif def1.type == "tool" and r1 then
return "tool", input1, input2
@ -84,7 +103,8 @@ local function distinguish_tool_and_material(input1, input2)
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)
if not stack or stack == "" then return "" end
local count = stack:get_count()
@ -99,6 +119,7 @@ end
-- Update the inventory slots of an anvil node.
-- meta: Metadata of anvil node
---@param meta NodeMetaRef
local function update_anvil_slots(meta)
local inv = meta:get_inventory()
local new_name = meta:get_string("set_name")
@ -159,7 +180,7 @@ local function update_anvil_slots(meta)
has_correct_material = true
end
else
if contains(repair, material_name) then
if table.indexof(repair, material_name) ~= -1 then
has_correct_material = true
else
for _, r in pairs(repair) do
@ -231,28 +252,32 @@ local function update_anvil_slots(meta)
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 inv = meta:get_inventory()
for i = 1, inv:get_size("input") do
local stack = inv:get_stack("input", i)
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)
end
end
end
---@param pos Vector
---@param node node
local function damage_particles(pos, node)
minetest.add_particlespawner({
amount = 30,
time = 0.1,
minpos = vector.add(pos, {x=-0.5, y=-0.5, z=-0.5}),
maxpos = vector.add(pos, {x=0.5, y=-0.25, z=0.5}),
minvel = {x=-0.5, y=0.05, z=-0.5},
maxvel = {x=0.5, y=0.3, z=0.5},
minacc = {x=0, y=-9.81, z=0},
maxacc = {x=0, y=-9.81, z=0},
minpos = vector.offset(pos, -0.5, -0.5, -0.5),
maxpos = vector.offset(pos, 0.5, -0.25, 0.5),
minvel = vector.new(-0.5, 0.05, -0.5),
maxvel = vector.new(0.5, 0.3, 0.5),
minacc = vector.new(0, -9.81, 0),
maxacc = vector.new(0, -9.81, 0),
minexptime = 0.1,
maxexptime = 0.5,
minsize = 0.4,
@ -267,12 +292,12 @@ local function destroy_particles(pos, node)
minetest.add_particlespawner({
amount = math.random(20, 30),
time = 0.1,
minpos = vector.add(pos, {x=-0.4, y=-0.4, z=-0.4}),
maxpos = vector.add(pos, {x=0.4, y=0.4, z=0.4}),
minvel = {x=-0.5, y=-0.1, z=-0.5},
maxvel = {x=0.5, y=0.2, z=0.5},
minacc = {x=0, y=-9.81, z=0},
maxacc = {x=0, y=-9.81, z=0},
minpos = vector.offset(pos, -0.4, -0.4, -0.4),
maxpos = vector.offset(pos, 0.4, 0.4, 0.4),
minvel = vector.new(-0.5, -0.1, -0.5),
maxvel = vector.new(0.5, 0.2, 0.5),
minacc = vector.new(0, -9.81, 0),
maxacc = vector.new(0, -9.81, 0),
minexptime = 0.2,
maxexptime = 0.65,
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.remove_node(pos)
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
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 r = math.random(1, 100)
-- 12% chance
@ -321,6 +347,8 @@ local function damage_anvil_by_using(pos)
end
end
---@param pos Vector
---@param distance number
local function damage_anvil_by_falling(pos, distance)
local r = math.random(1, 100)
if distance > 1 then
@ -330,16 +358,19 @@ local function damage_anvil_by_falling(pos, distance)
end
end
---@type nodebox
local anvilbox = {
type = "fixed",
fixed = {
{ -8 / 16, -8 / 16, -6 / 16, 8 / 16, 8 / 16, 6 / 16 },
},
}
---@type node_definition
local anvildef = {
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" },
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"),
paramtype = "light",
sunlight_propagates = true,
@ -353,7 +384,7 @@ local anvildef = {
{ -5 / 16, -4 / 16, -4 / 16, 5 / 16, -3 / 16, 4 / 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 },
}
},
},
selection_box = anvilbox,
collision_box = anvilbox,
@ -504,22 +535,20 @@ local anvildef = {
minetest.record_protection_violation(pos, sender_name)
return
end
if fields.name_button or fields.name then
local set_name
if fields.name == nil then
set_name = ""
else
set_name = fields.name
end
if fields.name then
local meta = minetest.get_meta(pos)
-- 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)
update_anvil_slots(meta)
meta:set_string("formspec", get_anvil_formspec(set_name))
end
end,
}
if minetest.get_modpath("screwdriver") then
anvildef.on_rotate = screwdriver.rotate_simple
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!")
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 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("• 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 + 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("• 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 + 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("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.groups.anvil = 2
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)
anvildef2.description = S("Very Damaged Anvil")
anvildef2._doc_items_create_entry = false
anvildef2.groups.anvil = 3
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_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:iron_ingot", "" },
{ "mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot" },
}
},
})
end

@ -8,6 +8,7 @@ local open_barrels = {}
local drop_content = mcl_util.drop_items_from_meta_container("main")
---@param pos Vector
local function on_blast(pos)
local node = minetest.get_node(pos)
drop_content(pos, node)
@ -47,15 +48,18 @@ local function barrel_open(pos, node, clicker)
minetest.show_formspec(playername,
"mcl_barrels:barrel_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z,
table.concat({
"size[9,8.75]",
"label[0,0;"..F(C("#313131", name)).."]",
"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,4.0;"..F(C("#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),
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"list[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main;0.375,0.75;9,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[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";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)
end
---@param pos Vector
local function close_forms(pos)
local players = minetest.get_connected_players()
local formname = "mcl_barrels:barrel_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z
@ -76,15 +81,18 @@ local function close_forms(pos)
end
end
---@param pos Vector
local function update_after_close(pos)
local node = minetest.get_node_or_nil(pos)
if not node then return end
if node.name == "mcl_barrels:barrel_open" then
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
---@param player ObjectRef
local function close_barrel(player)
local name = player:get_player_name()
local open = open_barrels[name]
@ -106,7 +114,9 @@ minetest.register_node("mcl_barrels:barrel_closed", {
paramtype = "light",
paramtype2 = "facedir",
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
end,
stack_max = 64,
@ -155,7 +165,15 @@ minetest.register_node("mcl_barrels:barrel_open", {
drop = "mcl_barrels:barrel_closed",
stack_max = 64,
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_take = 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" },
{ "group:wood", "group:wood_slab", "group:wood" },
}
},
})
minetest.register_craft({

@ -1,5 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname())
local C = minetest.colorize
local F = minetest.formspec_escape
local LIGHT_ACTIVE_FURNACE = 13
@ -8,60 +9,82 @@ local LIGHT_ACTIVE_FURNACE = 13
--
local function active_formspec(fuel_percent, item_percent)
return "size[9,8.75]"..
"label[0,4;"..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[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Blast Furnace"))).."]"..
"list[context;src;2.75,0.5;1,1;]"..
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(2.75,2.5,1,1)..
"list[context;dst;5.75,1.5;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:"..
(100-fuel_percent)..":default_furnace_fire_fg.png]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[lowpart:"..
(item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
return table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Blast Furnace"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
"list[context;src;3.5,0.75;1,1;]",
"image[3.5,2;1,1;default_furnace_fire_bg.png^[lowpart:" ..
(100 - fuel_percent) .. ":default_furnace_fire_fg.png]",
mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;fuel;3.5,3.25;1,1;]",
"image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[lowpart:" ..
(item_percent) .. ":gui_furnace_arrow_fg.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.
-- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
"listring[context;fuel]"..
"listring[current_player;main]"
"listring[context;dst]",
"listring[current_player;main]",
"listring[context;src]",
"listring[current_player;main]",
"listring[context;fuel]",
"listring[current_player;main]",
})
end
local inactive_formspec = "size[9,8.75]"..
"label[0,4;"..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[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Blast Furnace"))).."]"..
"list[context;src;2.75,0.5;1,1;]"..
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(2.75,2.5,1,1)..
"list[context;dst;5.75,1.5;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]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[transformR270]"..
local inactive_formspec = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Blast Furnace"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
"list[context;src;3.5,0.75;1,1;]",
"image[3.5,2;1,1;default_furnace_fire_bg.png]",
mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;fuel;3.5,3.25;1,1;]",
"image[5.25,2;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.
-- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
"listring[context;fuel]"..
"listring[current_player;main]"
"listring[context;dst]",
"listring[current_player;main]",
"listring[context;src]",
"listring[current_player;main]",
"listring[context;fuel]",
"listring[current_player;main]",
})
local receive_fields = function(pos, formname, fields, sender)
if fields.craftguide then
@ -160,17 +183,17 @@ local function spawn_flames(pos, param2)
local minrelpos, maxrelpos
local dir = minetest.facedir_to_dir(param2)
if dir.x > 0 then
minrelpos = { x = -0.6, y = -0.05, z = -0.25 }
maxrelpos = { x = -0.55, y = -0.45, z = 0.25 }
minrelpos = vector.new(-0.6, -0.05, -0.25)
maxrelpos = vector.new(-0.55, -0.45, 0.25)
elseif dir.x < 0 then
minrelpos = { x = 0.55, y = -0.05, z = -0.25 }
maxrelpos = { x = 0.6, y = -0.45, z = 0.25 }
minrelpos = vector.new(0.55, -0.05, -0.25)
maxrelpos = vector.new(0.6, -0.45, 0.25)
elseif dir.z > 0 then
minrelpos = { x = -0.25, y = -0.05, z = -0.6 }
maxrelpos = { x = 0.25, y = -0.45, z = -0.55 }
minrelpos = vector.new(-0.25, -0.05, -0.6)
maxrelpos = vector.new(0.25, 0.45, -0.55)
elseif dir.z < 0 then
minrelpos = { x = -0.25, y = -0.05, z = 0.55 }
maxrelpos = { x = 0.25, y = -0.45, z = 0.6 }
minrelpos = vector.new(-0.25, -0.05, 0.55)
maxrelpos = vector.new(0.25, -0.45, 0.6)
else
return
end
@ -179,8 +202,8 @@ local function spawn_flames(pos, param2)
time = 0,
minpos = vector.add(pos, minrelpos),
maxpos = vector.add(pos, maxrelpos),
minvel = { x = -0.01, y = 0, z = -0.01 },
maxvel = { x = 0.01, y = 0.1, z = 0.01 },
minvel = vector.new(-0.01, 0, -0.01),
maxvel = vector.new(0.01, 0.1, 0.01),
minexptime = 0.3,
maxexptime = 0.6,
minsize = 0.4,
@ -415,7 +438,8 @@ end
minetest.register_node("mcl_blast_furnace:blast_furnace", {
description = S("Blast 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 =
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" ..
@ -442,8 +466,7 @@ minetest.register_node("mcl_blast_furnace:blast_furnace", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1)
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(p, stack)
minetest.add_item(vector.offset(pos, math.random(0, 10) / 10 - 0.5, 0, math.random(0, 10) / 10 - 0.5), stack)
end
end
meta:from_table(meta2)
@ -499,8 +522,10 @@ minetest.register_node("mcl_blast_furnace:blast_furnace_active", {
tiles = {
"blast_furnace_top.png", "blast_furnace_top.png",
"blast_furnace_side.png", "blast_furnace_side.png",
"blast_furnace_side.png", {name = "blast_furnace_front_on.png",
animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 48}},
"blast_furnace_side.png", {
name = "blast_furnace_front_on.png",
animation = { type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 48 }
},
},
paramtype2 = "facedir",
paramtype = "light",
@ -519,7 +544,11 @@ minetest.register_node("mcl_blast_furnace:blast_furnace_active", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1)
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)
end
end
@ -570,4 +599,3 @@ minetest.register_lbm({
spawn_flames(pos, node.param2)
end,
})

@ -85,7 +85,8 @@ local function write(itemstack, user, pointed_thing)
local node = minetest.get_node(pointed_thing.under)
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
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
@ -106,7 +107,8 @@ local function read(itemstack, user, pointed_thing)
local node = minetest.get_node(pointed_thing.under)
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
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
@ -125,7 +127,9 @@ minetest.register_craftitem("mcl_books:writable_book", {
description = S("Book and Quill"),
_tt_help = S("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."),
inventory_image = "mcl_books_book_writable.png",
groups = { book = 1 },
@ -151,10 +155,13 @@ minetest.register_on_player_receive_fields(function ( player, formname, fields )
local formspec = "size[8,9]" ..
header ..
"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:")))..";]"..
"label[0.75,1.5;"..minetest.formspec_escape(minetest.colorize("#404040", S("by @1", name))).."]"..
"field[0.75,1;7.25,1;title;" ..
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")) .. "]" ..
"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")) .. "]"
minetest.show_formspec(player:get_player_name(), "mcl_books:signing", formspec)
end
@ -202,10 +209,14 @@ end
-- Written Book
minetest.register_craftitem("mcl_books: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_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."),
_doc_items_longdesc = S(
"Written books contain some text written by someone. They can be read and copied, but not edited."
),
_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",
groups = { not_in_creative_inventory = 1, book = 1, no_rename = 1 },
stack_max = 16,
@ -367,6 +378,9 @@ local function protection_check_put_take(pos, listname, index, stack, player)
end
end
---@param pos Vector
---@param node node
---@param clicker ObjectRef
local function bookshelf_gui(pos, node, clicker)
if not bookshelf_inv then return end
local name = minetest.get_meta(pos):get_string("name")
@ -380,15 +394,19 @@ local function bookshelf_gui(pos, node, clicker)
minetest.show_formspec(playername,
"mcl_books:bookshelf_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z,
table.concat({
"size[9,8.75]",
"label[0,0;"..F(C("#313131", name)).."]",
"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,4.0;"..F(C("#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),
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3, 0, "mcl_book_book_empty_slot.png"),
"list[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main;0.375,0.75;9,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[nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ";main]",
"listring[current_player;main]",
})
@ -413,8 +431,14 @@ minetest.register_node("mcl_books:bookshelf", {
stack_max = 64,
is_ground_content = false,
groups = {
handy=1, axey=1, deco_block=1, material_wood=1,
flammable=3, fire_encouragement=30, fire_flammability=20, container=1
handy = 1,
axey = 1,
deco_block = 1,
material_wood = 1,
flammable = 3,
fire_encouragement = 30,
fire_flammability = 20,
container = 1
},
drop = "mcl_books:book 3",
sounds = wood_sound,
@ -464,4 +488,3 @@ minetest.register_craft({
recipe = "mcl_books:bookshelf",
burntime = 15,
})

@ -1,4 +1,13 @@
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")
-- Christmas chest setup
@ -50,7 +59,7 @@ local entity_animations = {
speed = 25,
open = { x = 0, y = 7 },
close = { x = 13, y = 20 },
}
},
}
minetest.register_entity("mcl_chests:chest", {
@ -72,7 +81,8 @@ minetest.register_entity("mcl_chests:chest", {
self.players[playername] = true
if not self.is_open then
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
end
end,
@ -85,7 +95,9 @@ minetest.register_entity("mcl_chests:chest", {
return
end
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
end
end,
@ -136,7 +148,7 @@ minetest.register_entity("mcl_chests:chest", {
})
local function get_entity_pos(pos, dir, double)
pos = vector.new(pos)
pos = vector.copy(pos)
if double then
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))
@ -158,7 +170,8 @@ local function get_entity_info(pos, param2, double, dir, entity_pos)
return dir, get_entity_pos(pos, dir, double)
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)
local obj = minetest.add_entity(entity_pos, "mcl_chests:chest")
local luaentity = obj:get_luaentity()
@ -166,9 +179,12 @@ local function create_entity(pos, node_name, textures, param2, double, sound_pre
return luaentity
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)
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
local no_rotate, simple_rotate
@ -179,7 +195,9 @@ if minetest.get_modpath("screwdriver") then
local nodename = node.name
local nodedef = minetest.registered_nodes[nodename]
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
return false
end
@ -204,10 +222,21 @@ end]]
-- 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 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
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
@ -221,6 +250,7 @@ local function protection_check_move(pos, from_list, from_index, to_list, to_ind
return count
end
end
local function protection_check_put_take(pos, listname, index, stack, player)
local name = player:get_player_name()
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
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)
elseif node.name == "mcl_chests:trapped_chest_on_left" then
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)
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")
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)
end
end
@ -268,7 +301,9 @@ local function player_chest_close(player)
return
end
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
chest_update_after_close(open_chest.pos)
@ -276,7 +311,9 @@ local function player_chest_close(player)
end
-- 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
if not drop then
drop = "mcl_chests:" .. basename
@ -361,10 +398,9 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
drawtype = "mesh",
mesh = "mcl_chests_chest.b3d",
tiles = small_textures,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
use_texture_alpha = "opaque",
paramtype = "light",
paramtype2 = "facedir",
stack_max = 64,
sounds = mcl_sounds.node_sound_wood_defaults(),
groups = { deco_block = 1 },
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()
for p = 1, #players do
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
@ -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 },
},
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_sound = "default_chest",
_chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest",
paramtype = "light",
paramtype2 = "facedir",
stack_max = 64,
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,
sounds = mcl_sounds.node_sound_wood_defaults(),
on_construct = function(pos)
@ -435,19 +480,26 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
-- BEGIN OF LISTRING WORKAROUND
inv:set_size("input", 1)
-- 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 })
local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right")
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")
elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..canonical_basename.."_small" then
create_entity(p, "mcl_chests:" .. canonical_basename .. "_left", left_textures, param2, true,
"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 })
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")
minetest.swap_node(p, { name = "mcl_chests:" .. canonical_basename .. "_right", param2 = param2 })
else
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,
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
minetest.show_formspec(clicker:get_player_name(),
"mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z,
"size[9,8.75]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]"..
"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,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)..
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]"..
"listring[current_player;main]")
sf("mcl_chests:%s_%s_%s_%s", canonical_basename, pos.x, pos.y, pos.z),
table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"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.x, pos.y, pos.z),
"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;]",
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]",
})
)
if on_rightclick_addendum then
on_rightclick_addendum(pos, node, clicker)
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,
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 },
},
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_sound = "default_chest",
_chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest",
paramtype = "light",
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,
is_ground_content = false,
sounds = mcl_sounds.node_sound_wood_defaults(),
@ -590,7 +658,8 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
else
return 0
end
end]]--
end]]
--
-- END OF LISTRING WORKAROUND
else
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)
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_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
-- 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
minetest.show_formspec(clicker:get_player_name(),
"mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z,
"size[9,11.5]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]"..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]"..
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;]"..
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)..
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.x, pos.y, pos.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_other.x, pos_other.y, pos_other.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;]",
--BEGIN OF LISTRING WORKAROUND
"listring[current_player;main]"..
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";input]"..
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND
"listring[current_player;main]" ..
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";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.x, pos.y, pos.z),
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
})
)
if on_rightclick_addendum_left then
on_rightclick_addendum_left(pos, node, clicker)
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,
mesecons = mesecons,
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 },
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true,
groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2},
use_texture_alpha = "clip",
groups = {
handy = 1,
axey = 1,
container = 6,
not_in_creative_inventory = 1,
material_wood = 1,
flammable = -1,
double_chest = 2
},
drop = drop,
is_ground_content = false,
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)
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
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
if minetest.registered_nodes[minetest.get_node(vector.offset(pos, 0, 1, 0)).name].groups.opaque == 1
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
return false
end
@ -788,33 +876,40 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
end
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
"listring[current_player;main]"..
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";input]"..
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND
"listring[current_player;main]" ..
"listring[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main]"..
"listring[current_player;main]"..
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]")
sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
})
)
if on_rightclick_addendum_right then
on_rightclick_addendum_right(pos, node, clicker)
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,
mesecons = mesecons,
on_rotate = no_rotate,
@ -838,6 +933,15 @@ register_chest("chest",
{
small = tiles_chest_normal_small,
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
)
@ -851,16 +955,20 @@ register_chest("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."),
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,
nil,
{receptor = {
{
receptor = {
state = mesecon.state.off,
rules = trapped_chest_mesecons_rules,
}},
},
},
function(pos, node, clicker)
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)
end,
function(pos, node, clicker)
@ -868,7 +976,8 @@ register_chest("trapped_chest",
meta:set_int("players", 1)
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)
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)
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)
end
)
register_chest("trapped_chest_on",
nil, nil, nil, nil, traptiles, true,
{receptor = {
{
receptor = {
state = mesecon.state.on,
rules = trapped_chest_mesecons_rules,
}},
},
},
nil, nil, nil,
"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" },
}
},
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_chests:chest",
burntime = 15
burntime = 15,
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_chests:trapped_chest",
burntime = 15
burntime = 15,
})
minetest.register_node("mcl_chests:ender_chest", {
description = S("Ender Chest"),
_tt_help = S("27 interdimensional inventory slots") .. "\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."),
_tt_help = S("27 interdimensional inventory slots") ..
"\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."),
drawtype = "mesh",
mesh = "mcl_chests_chest.b3d",
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",
paramtype2 = "facedir",
stack_max = 64,
groups = { deco_block = 1 },
sounds = mcl_sounds.node_sound_stone_defaults(),
on_construct = function(pos, node)
on_construct = function(pos)
local node = minetest.get_node(pos)
node.name = "mcl_chests:ender_chest_small"
minetest.set_node(pos, node)
end,
})
local formspec_ender_chest = "size[9,8.75]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Ender Chest"))).."]"..
"list[current_player;enderchest;0,0.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"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)..
"listring[current_player;enderchest]"..
"listring[current_player;main]"
local formspec_ender_chest = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Ender Chest"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"list[current_player;enderchest;0.375,0.75;9,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[current_player;enderchest]",
"listring[current_player;main]",
})
minetest.register_node("mcl_chests:ender_chest_small", {
description = S("Ender Chest"),
_tt_help = S("27 interdimensional inventory slots") .. "\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."),
_tt_help = S("27 interdimensional inventory slots") ..
"\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."),
drawtype = "nodebox",
node_box = {
@ -1013,7 +1135,7 @@ minetest.register_node("mcl_chests:ender_chest_small", {
_chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest",
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
-- have an inventory on its own
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(),
drop = "mcl_core:obsidian 8",
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,
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
return false
end
minetest.show_formspec(clicker:get_player_name(), "mcl_chests:ender_chest_"..clicker:get_player_name(), 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")
minetest.show_formspec(clicker:get_player_name(), "mcl_chests:ender_chest_" .. clicker:get_player_name(),
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,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then
@ -1070,7 +1195,7 @@ minetest.register_craft({
{ "mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian" },
{ "mcl_core:obsidian", "mcl_end:ender_eye", "mcl_core:obsidian" },
{ "mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian" },
}
},
})
-- Shulker boxes
@ -1113,21 +1238,29 @@ local shulker_mob_textures = {
}
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)
if name == "" then
if not name or name == "" then
name = S("Shulker Box")
end
return "size[9,8.75]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]"..
"list[context;main;0,0.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"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)..
"listring[context;main]"..
"listring[current_player;main]"
return table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"list[context;main;0.375,0.75;9,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]",
})
end
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
if mod_doc 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.")
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.")
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.")
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")
else
create_entry = false
@ -1161,10 +1296,18 @@ for color, desc in pairs(boxtypes) do
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
tiles = { mob_texture },
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
use_texture_alpha = "opaque",
drawtype = "mesh",
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,
sounds = mcl_sounds.node_sound_stone_defaults(),
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 },
},
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_sound = "mcl_chests_shulker",
_chest_entity_mesh = "mcl_chests_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,
sounds = mcl_sounds.node_sound_stone_defaults(),
stack_max = 1,
@ -1244,7 +1396,8 @@ for color, desc in pairs(boxtypes) do
meta:set_string("formspec", formspec_shulker_box(nil))
local inv = meta:get_inventory()
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,
after_place_node = function(pos, placer, itemstack, pointed_thing)
local nmeta = minetest.get_meta(pos)
@ -1266,7 +1419,8 @@ for color, desc in pairs(boxtypes) do
end
end,
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,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then
@ -1317,14 +1471,16 @@ for color, desc in pairs(boxtypes) do
})
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_small", "nodes", "mcl_chests:"..color.."_shulker_box_small")
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_small", "nodes",
"mcl_chests:" .. color .. "_shulker_box_small")
end
minetest.register_craft({
type = "shapeless",
output = "mcl_chests:" .. color .. "_shulker_box",
recipe = { "group:shulker_box", "mcl_dye:"..color }
recipe = { "group:shulker_box", "mcl_dye:" .. color },
})
end
@ -1334,7 +1490,7 @@ minetest.register_craft({
{ "mcl_mobitems:shulker_shell" },
{ "mcl_chests:chest" },
{ "mcl_mobitems:shulker_shell" },
}
},
})
-- 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_def = minetest.registered_nodes[node_name]
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
minetest.register_lbm({
@ -1376,7 +1533,9 @@ minetest.register_lbm({
minetest.register_lbm({
label = "Replace old chest nodes",
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,
action = function(pos, node)
local node_name = node.name
@ -1399,7 +1558,8 @@ minetest.register_lbm({
-- Fixes redstone weirdness.
label = "Disable active 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,
action = function(pos, node)
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({
label = "Update shulker box formspecs (0.60.0)",
name = "mcl_chests:update_shulker_box_formspecs_0_60_0",
label = "Update shulker box formspecs (0.72.0)",
name = "mcl_chests:update_shulker_box_formspecs_0_72_0",
nodenames = { "group:shulker_box" },
run_at_every_load = false,
action = function(pos, node)
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,
})

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

@ -2,7 +2,8 @@ local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
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
function mcl_enchanting.get_enchantments(itemstack)
@ -54,11 +55,13 @@ end
function mcl_enchanting.get_enchantment_description(enchantment, level)
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
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
function mcl_enchanting.get_enchanted_itemstring(itemname)
@ -79,7 +82,8 @@ function mcl_enchanting.not_enchantable_on_enchanting_table(itemname)
end
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
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
local incompatible_level = item_enchantments[incompatible]
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
@ -169,7 +174,9 @@ function mcl_enchanting.combine(itemstack, combine_with)
local itemname = itemstack:get_name()
local combine_name = combine_with:get_name()
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
end
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)]
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()
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
end
itemstack = ItemStack(itemstack)
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 + 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)
local enchantments = {}
@ -387,7 +398,6 @@ function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_leve
enchantments[selected_enchantment] = enchantment_power
mcl_enchanting.enchant(itemstack, selected_enchantment, enchantment_power)
end
until not no_reduced_bonus_chance and mcl_enchanting.random(pr) >= (enchantment_level + 1) / 50
return enchantments, description
@ -397,13 +407,15 @@ function mcl_enchanting.generate_random_enchantments_reliable(itemstack, enchant
local enchantments
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
return enchantments
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)
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)
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
return stack
@ -426,7 +439,8 @@ function mcl_enchanting.get_random_glyph_row()
local glyphs = ""
local x = 1.3
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
end
return glyphs
@ -491,28 +505,33 @@ function mcl_enchanting.show_enchanting_formspec(player)
local inv = player:get_inventory()
local num_bookshelves = meta:get_int("mcl_enchanting:num_bookshelves")
local table_name = meta:get_string("mcl_enchanting:table_name")
local formspec = ""
.. "size[9.07,8.6;]"
.. "formspec_version[3]"
.. "label[0,0;" .. C("#313131") .. F(table_name) .. "]"
.. mcl_formspec.get_itemslot_bg(0.2, 2.4, 1, 1)
.. "list[current_player;enchanting_item;0.2,2.4;1,1]"
.. mcl_formspec.get_itemslot_bg(1.1, 2.4, 1, 1)
.. "image[1.1,2.4;1,1;mcl_enchanting_lapis_background.png]"
.. "list[current_player;enchanting_lapis;1.1,2.4;1,1]"
.. "label[0,4;" .. C("#313131") .. F(S("Inventory")).."]"
.. mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3)
.. mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1)
.. "list[current_player;main;0,4.5;9,3;9]"
.. "listring[current_player;enchanting_item]"
.. "listring[current_player;main]"
.. "listring[current_player;enchanting]"
.. "listring[current_player;main]"
.. "listring[current_player;enchanting_lapis]"
.. "listring[current_player;main]"
.. "list[current_player;main;0,7.74;9,1;]"
.. "real_coordinates[true]"
.. "image[3.15,0.6;7.6,4.1;mcl_enchanting_button_background.png]"
local formspec = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color) .. table_name) .. "]",
mcl_formspec.get_itemslot_bg_v4(1, 3.25, 1, 1),
"list[current_player;enchanting_item;1,3.25;1,1]",
mcl_formspec.get_itemslot_bg_v4(2.25, 3.25, 1, 1),
"image[2.25,3.25;1,1;mcl_enchanting_lapis_background.png]",
"list[current_player;enchanting_lapis;2.25,3.25;1,1]",
"image[4.125,0.56;7.25,4.1;mcl_enchanting_button_background.png]",
"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[current_player;enchanting_item]",
"listring[current_player;main]",
"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 player_levels = mcl_experience.get_level(player)
local y = 0.65
@ -526,18 +545,44 @@ function mcl_enchanting.show_enchanting_formspec(player)
local ending = (can_enchant and "" or "_off")
local hover_ending = (can_enchant and "_hovered" or "_off")
formspec = formspec
.. "container[3.2," .. 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 .. ";]"
.. "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.25,1.3;button_" .. i .. ";]"
.. (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 "")
.. "container_end[]"
y = y + 1.35
y = y + 1.3
end
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)
end
@ -603,7 +648,8 @@ function mcl_enchanting.is_enchanting_inventory_action(action, inventory, invent
end
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 action == "move" then
local listname = inventory_info.to_list
@ -650,8 +696,10 @@ end
function mcl_enchanting.set_book_animation(self, 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]
self.object:set_animation({x = start, y = stop}, mcl_enchanting.book_animation_speed, 0, mcl_enchanting.book_animation_loop[anim] or false)
local start, stop = mcl_enchanting.book_animation_steps[anim_index],
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.anim_length = (stop - start) / 40
end

@ -1,5 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname())
local C = minetest.colorize
local F = minetest.formspec_escape
local LIGHT_ACTIVE_FURNACE = 13
@ -8,60 +9,82 @@ local LIGHT_ACTIVE_FURNACE = 13
--
local function active_formspec(fuel_percent, item_percent)
return "size[9,8.75]"..
"label[0,4;"..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[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Furnace"))).."]"..
"list[context;src;2.75,0.5;1,1;]"..
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(2.75,2.5,1,1)..
"list[context;dst;5.75,1.5;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:"..
(100-fuel_percent)..":default_furnace_fire_fg.png]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[lowpart:"..
(item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
return table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Furnace"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
"list[context;src;3.5,0.75;1,1;]",
"image[3.5,2;1,1;default_furnace_fire_bg.png^[lowpart:" ..
(100 - fuel_percent) .. ":default_furnace_fire_fg.png]",
mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;fuel;3.5,3.25;1,1;]",
"image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[lowpart:" ..
(item_percent) .. ":gui_furnace_arrow_fg.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.
-- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
"listring[context;fuel]"..
"listring[current_player;main]"
"listring[context;dst]",
"listring[current_player;main]",
"listring[context;src]",
"listring[current_player;main]",
"listring[context;fuel]",
"listring[current_player;main]",
})
end
local inactive_formspec = "size[9,8.75]"..
"label[0,4;"..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[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Furnace"))).."]"..
"list[context;src;2.75,0.5;1,1;]"..
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(2.75,2.5,1,1)..
"list[context;dst;5.75,1.5;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]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[transformR270]"..
local inactive_formspec = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Furnace"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
"list[context;src;3.5,0.75;1,1;]",
"image[3.5,2;1,1;default_furnace_fire_bg.png]",
mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;fuel;3.5,3.25;1,1;]",
"image[5.25,2;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.
-- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
"listring[context;fuel]"..
"listring[current_player;main]"
"listring[context;dst]",
"listring[current_player;main]",
"listring[context;src]",
"listring[current_player;main]",
"listring[context;fuel]",
"listring[current_player;main]",
})
local receive_fields = function(pos, formname, fields, sender)
if fields.craftguide then
@ -465,7 +488,8 @@ minetest.register_node("mcl_furnaces:furnace", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1)
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)
end
end
@ -541,7 +565,8 @@ minetest.register_node("mcl_furnaces:furnace_active", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1)
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)
end
end

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

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

@ -1,11 +1,13 @@
--[[
By EliasFleckenstein03 and Code-Sploit
]]
-- By EliasFleckenstein03 and Code-Sploit
local S = minetest.get_translator("mcl_smithing_table")
local F = minetest.formspec_escape
local C = minetest.colorize
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)
local def = itemstack:get_definition()
@ -29,28 +31,48 @@ function mcl_smithing_table.upgrade_item(itemstack)
return itemstack
end
-- Badly copied over from mcl_anvils
-- ToDo: Make better formspec
local formspec = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
local formspec = "size[9,9]" ..
"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]"
"label[4.125,0.375;" .. F(C(mcl_formspec.label_color, S("Upgrade Gear"))) .. "]",
"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 inv = minetest.get_meta(pos):get_inventory()
local upgraded_item
@ -66,7 +88,6 @@ minetest.register_node("mcl_smithing_table:table", {
description = S("Smithing table"),
-- ToDo: Add _doc_items_longdesc and _doc_items_usagehelp
stack_max = 64,
groups = { pickaxey = 2, deco_block = 1 },
tiles = {
@ -92,7 +113,8 @@ minetest.register_node("mcl_smithing_table:table", {
end,
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()
end
@ -141,5 +163,5 @@ minetest.register_craft({
{ "mcl_core:iron_ingot", "mcl_core:iron_ingot", "" },
{ "group:wood", "group:wood", "" },
{ "group:wood", "group:wood", "" }
}
},
})

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

@ -1,5 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname())
local C = minetest.colorize
local F = minetest.formspec_escape
local LIGHT_ACTIVE_FURNACE = 13
@ -8,60 +9,82 @@ local LIGHT_ACTIVE_FURNACE = 13
--
local function active_formspec(fuel_percent, item_percent)
return "size[9,8.75]"..
"label[0,4;"..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[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Smoker"))).."]"..
"list[context;src;2.75,0.5;1,1;]"..
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(2.75,2.5,1,1)..
"list[context;dst;5.75,1.5;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:"..
(100-fuel_percent)..":default_furnace_fire_fg.png]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[lowpart:"..
(item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
return table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Smoker"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
"list[context;src;3.5,0.75;1,1;]",
"image[3.5,2;1,1;default_furnace_fire_bg.png^[lowpart:" ..
(100 - fuel_percent) .. ":default_furnace_fire_fg.png]",
mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;fuel;3.5,3.25;1,1;]",
"image[5.25,2;1.5,1;gui_furnace_arrow_bg.png^[lowpart:" ..
(item_percent) .. ":gui_furnace_arrow_fg.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.
-- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
"listring[context;fuel]"..
"listring[current_player;main]"
"listring[context;dst]",
"listring[current_player;main]",
"listring[context;src]",
"listring[current_player;main]",
"listring[context;fuel]",
"listring[current_player;main]",
})
end
local inactive_formspec = "size[9,8.75]"..
"label[0,4;"..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[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Smoker"))).."]"..
"list[context;src;2.75,0.5;1,1;]"..
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(2.75,2.5,1,1)..
"list[context;dst;5.75,1.5;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]"..
"image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[transformR270]"..
local inactive_formspec = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Smoker"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(3.5, 0.75, 1, 1),
"list[context;src;3.5,0.75;1,1;]",
"image[3.5,2;1,1;default_furnace_fire_bg.png]",
mcl_formspec.get_itemslot_bg_v4(3.5, 3.25, 1, 1),
"list[context;fuel;3.5,3.25;1,1;]",
"image[5.25,2;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.
-- TODO: Add it back when the Minetest bug is fixed.
--"image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
--"tooltip[craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
"listring[context;fuel]"..
"listring[current_player;main]"
"listring[context;dst]",
"listring[current_player;main]",
"listring[context;src]",
"listring[current_player;main]",
"listring[context;fuel]",
"listring[current_player;main]",
})
local receive_fields = function(pos, formname, fields, sender)
if fields.craftguide then
@ -415,7 +438,8 @@ end
minetest.register_node("mcl_smoker:smoker", {
description = S("Smoker"),
_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 =
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" ..
@ -442,7 +466,11 @@ minetest.register_node("mcl_smoker:smoker", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1)
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)
end
end
@ -499,8 +527,10 @@ minetest.register_node("mcl_smoker:smoker_active", {
tiles = {
"smoker_top.png", "smoker_bottom.png",
"smoker_side.png", "smoker_side.png",
"smoker_side.png", {name = "smoker_front_on.png",
animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 48}},
"smoker_side.png", {
name = "smoker_front_on.png",
animation = { type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 48 }
},
},
paramtype2 = "facedir",
paramtype = "light",
@ -519,7 +549,11 @@ minetest.register_node("mcl_smoker:smoker_active", {
for _, listname in ipairs({ "src", "dst", "fuel" }) do
local stack = inv:get_stack(listname, 1)
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)
end
end

@ -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.

@ -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
})

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

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

@ -1,5 +1,5 @@
name = mcl_meshhand
author = jordan4ibanez
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

@ -1,3 +1,4 @@
local string = string
local sf = string.format
-- Minetest 0.4 mod: player
@ -11,7 +12,8 @@ local animation_blend = 0
local function get_mouse_button(player)
local controls = player:get_player_control()
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
return true
else
@ -49,7 +51,7 @@ function mcl_player.player_get_animation(player)
model = player_model[name],
textures = textures,
animation = player_anim[name],
visibility = player_visibility[name]
visibility = player_visible[name]
}
end
@ -133,6 +135,13 @@ function mcl_player.player_set_armor(player, texture)
update_player_textures(player)
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)
local name = player:get_player_name()
local model = player_model[name]
@ -166,6 +175,7 @@ minetest.register_on_joinplayer(function(player)
mcl_player.player_attached[name] = false
player_visible[name] = true
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_fov(86.1) -- see <https://minecraft.gamepedia.com/Options#Video_settings>>>>
end)
@ -225,7 +235,9 @@ minetest.register_globalstep(function(dtime)
or walking and velocity.z > 0.35
or walking and velocity.z < -0.35 then
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
player_anim[name] = nil
player_sneak[name] = controls.sneak
@ -234,7 +246,8 @@ minetest.register_globalstep(function(dtime)
player_set_animation(player, "swim_walk_mine", animation_speed_mod)
elseif not controls.sneak and head_in_water and is_sprinting == true then
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)
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)

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