1
0
mirror of https://bitbucket.org/minetest_gamers/x_enchanting.git synced 2025-06-29 06:11:20 +02:00

16 Commits

29 changed files with 453 additions and 134 deletions

15
.gitattributes vendored Normal file
View File

@ -0,0 +1,15 @@
# Creating an archive
.* export-ignore
assets export-ignore
scripts export-ignore
bin export-ignore
docs export-ignore
types export-ignore
*.zip export-ignore
bitbucket-pipelines.yml export-ignore
package.json export-ignore
package-lock.json export-ignore
screenshot*.png export-ignore
i18n.py export-ignore
config.ld export-ignore

View File

@ -1,8 +1,7 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999 Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc. Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
@ -55,7 +54,7 @@ modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be author's reputation will not be affected by problems that might be
introduced by others. introduced by others.
Finally, software patents pose a constant threat to the existence of Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a effectively restrict the users of a free program by obtaining a
@ -111,7 +110,7 @@ modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The "work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must former contains code derived from the library, whereas the latter must
be combined with the library in order to run. be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@ -158,7 +157,7 @@ Library.
You may charge a fee for the physical act of transferring a copy, You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a and you may at your option offer warranty protection in exchange for a
fee. fee.
2. You may modify your copy or copies of the Library or any portion 2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1 distribute such modifications or work under the terms of Section 1
@ -216,7 +215,7 @@ instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in that version instead if you wish.) Do not make any other change in
these notices. these notices.
Once this change is made in a given copy, it is irreversible for Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy. subsequent copies and derivative works made from that copy.
@ -267,7 +266,7 @@ Library will still fall under Section 6.)
distribute the object code for the work under the terms of Section 6. distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6, Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself. whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or 6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work work containing portions of the Library, and distribute that work
@ -329,7 +328,7 @@ restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you use both them and the Library together in an executable that you
distribute. distribute.
7. You may place library facilities that are a work based on the 7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined facilities not covered by this License, and distribute such a combined
@ -370,7 +369,7 @@ subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein. restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with You are not responsible for enforcing compliance by third parties with
this License. this License.
11. If, as a consequence of a court judgment or allegation of patent 11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues), infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or conditions are imposed on you (whether by court order, agreement or
@ -422,7 +421,7 @@ conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by license version number, you may choose any version ever published by
the Free Software Foundation. the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free 14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these, programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is write to the author to ask for permission. For software which is
@ -454,49 +453,3 @@ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES. DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -6,9 +6,10 @@ Adds Enchanting Mechanics and API.
## Features ## Features
* does not add new tools/items, it's using MT API to change existing items instead
* adds enchanting table * adds enchanting table
* supports all registered tools with known tool groups: pickaxe, shovel, axe, sword, e.g. `groups = {pickaxe = 1}` * supports all registered tools with known tool groups: pickaxe, shovel, axe, sword, e.g. `groups = {pickaxe = 1}`
* support all bows with group `{bow = 1}` * supports all bows with group `{bow = 1}`
* supports `default:bookshelf` or anything with `group:bookshelf` * supports `default:bookshelf` or anything with `group:bookshelf`
* enchanting trade is for `default:mese_crystal` or anything with `groups = {enchanting_trade = 1}` * enchanting trade is for `default:mese_crystal` or anything with `groups = {enchanting_trade = 1}`
* adds enchantability for all MT default tools, for custom tools the enchantability can be set in the item group, e.g. `groups = {enchantability = 15}` * adds enchantability for all MT default tools, for custom tools the enchantability can be set in the item group, e.g. `groups = {enchantability = 15}`
@ -97,6 +98,8 @@ groups: sword
Cause mobs to drop more items. This value is not used in the engine; it is the responsibility of the game/mod code to implement this. Cause mobs to drop more items. This value is not used in the engine; it is the responsibility of the game/mod code to implement this.
Supported: mobs_monster, mobs_animal, animalia
groups: sword groups: sword
#### Power #### Power
@ -184,7 +187,7 @@ GNU Lesser General Public License v2.1 or later (see included LICENSE file)
### Textures ### Textures
**CC BY-SA 4.0, Pixel Perfection by XSSheep**, https://minecraft.curseforge.com/projects/pixel-perfection-freshly-updated **CC-BY-SA-4.0, Pixel Perfection by XSSheep**, https://minecraft.curseforge.com/projects/pixel-perfection-freshly-updated
- x_enchanting_symbol_1.png - x_enchanting_symbol_1.png
- x_enchanting_symbol_2.png - x_enchanting_symbol_2.png
@ -213,7 +216,7 @@ GNU Lesser General Public License v2.1 or later (see included LICENSE file)
- x_enchanting_symbol_25.png - x_enchanting_symbol_25.png
- x_enchanting_symbol_26.png - x_enchanting_symbol_26.png
**LGPL-2.1-or-later, by SaKeL** **CC-BY-SA-4.0, by SaKeL**
- x_enchanting_image_button_disabled.png - x_enchanting_image_button_disabled.png
- x_enchanting_image_button.png - x_enchanting_image_button.png
@ -224,11 +227,15 @@ GNU Lesser General Public License v2.1 or later (see included LICENSE file)
- x_enchanting_scroll_mesh.png -- Derived from a texture TumeniNodes (CC BY-SA 3.0) - x_enchanting_scroll_mesh.png -- Derived from a texture TumeniNodes (CC BY-SA 3.0)
- x_enchanting_scroll_particle.png - x_enchanting_scroll_particle.png
- x_enchanting_table.png - x_enchanting_table.png
- x_enchanting_trade_slot.png - x_enchanting_gui_slot_bg.png -- Derived from texture Pixel Perfection by XSSheep (CC-BY-SA-4.0)
- x_enchanting_gui_cloth_bg.png -- Derived from texture Pixel Perfection by XSSheep (CC-BY-SA-4.0)
- x_enchanting_gui_cloth_trade_bg.png -- Derived from texture Pixel Perfection by XSSheep (CC-BY-SA-4.0)
- x_enchanting_gui_formbg.png -- Derived from texture Pixel Perfection by XSSheep (CC-BY-SA-4.0)
- x_enchanting_gui_hb_bg.png -- Derived from texture Pixel Perfection by XSSheep (CC-BY-SA-4.0)
### Models ### Models
**LGPL-2.1-or-later, by SaKeL** **CC-BY-SA-4.0, by SaKeL**
- x_enchanting_scroll.b3d - x_enchanting_scroll.b3d
- x_enchanting_table.obj - x_enchanting_table.obj

160
api.lua
View File

@ -1,4 +1,20 @@
default = minetest.global_exists('default') and default --[[@as MtgDefault]] --[[
X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to juraj.vajda@gmail.com
--]]
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
@ -290,6 +306,18 @@ local function get_table_length(table)
return length return length
end end
---Find element v of t satisfying f(v)
local function tableFind(t, f)
for _, v in ipairs(t) do
if f(v) then
return v
end
end
return nil
end
---@diagnostic disable-next-line: unused-local
function XEnchanting.has_tool_group(self, name) function XEnchanting.has_tool_group(self, name)
if minetest.get_item_group(name, 'pickaxe') > 0 then if minetest.get_item_group(name, 'pickaxe') > 0 then
return 'pickaxe' return 'pickaxe'
@ -323,10 +351,12 @@ function XEnchanting.set_tool_enchantability(self, tool_def)
}) })
end end
---@diagnostic disable-next-line: unused-local
function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantments) function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantments)
local tool_stack = ItemStack({ name = tool_def.name }) local tool_stack = ItemStack({ name = tool_def.name })
local tool_capabilities = tool_stack:get_tool_capabilities() local tool_capabilities = tool_stack:get_tool_capabilities()
---@diagnostic disable-next-line: unused-local
for i, enchantment in ipairs(enchantments) do for i, enchantment in ipairs(enchantments) do
-- Efficiency -- Efficiency
if enchantment.id == 'efficiency' then if enchantment.id == 'efficiency' then
@ -441,6 +471,7 @@ function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantment
return tool_capabilities return tool_capabilities
end end
---@diagnostic disable-next-line: unused-local
function XEnchanting.get_randomseed(self) function XEnchanting.get_randomseed(self)
return tonumber(tostring(os.time()):reverse():sub(1, 9)) --[[@as integer]] return tonumber(tostring(os.time()):reverse():sub(1, 9)) --[[@as integer]]
end end
@ -449,6 +480,7 @@ function XEnchanting.get_enchanted_descriptions(self, enchantments)
local enchantments_desc = {} local enchantments_desc = {}
local enchantments_desc_masked = {} local enchantments_desc_masked = {}
---@diagnostic disable-next-line: unused-local
for i, enchantment in ipairs(enchantments) do for i, enchantment in ipairs(enchantments) do
local add_roman_numbers = true local add_roman_numbers = true
@ -475,7 +507,7 @@ function XEnchanting.get_enchanted_descriptions(self, enchantments)
enchantments_desc = '\n' .. minetest.colorize('#AE81FF', S('Enchanted')) enchantments_desc = '\n' .. minetest.colorize('#AE81FF', S('Enchanted'))
.. '\n' .. table.concat(enchantments_desc, '\n') .. '\n' .. table.concat(enchantments_desc, '\n')
enchantments_desc_masked = table.concat(enchantments_desc_masked, '') .. '...?' enchantments_desc_masked = table.concat(enchantments_desc_masked, '') .. '..?'
return { return {
enchantments_desc = enchantments_desc, enchantments_desc = enchantments_desc,
@ -505,6 +537,7 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
---@type table<string, {["value"]: number}> ---@type table<string, {["value"]: number}>
local final_enchantments_meta = {} local final_enchantments_meta = {}
---@diagnostic disable-next-line: unused-local
for i, enchantment in ipairs(final_enchantments) do for i, enchantment in ipairs(final_enchantments) do
stack_meta:set_float('is_' .. enchantment.id, enchantment.value) stack_meta:set_float('is_' .. enchantment.id, enchantment.value)
-- store only necessary data, keeping the meta optimized -- store only necessary data, keeping the meta optimized
@ -536,6 +569,58 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
pos = pos, pos = pos,
max_hear_distance = 10 max_hear_distance = 10
}, true) }, true)
-- particles
local particlespawner_def = {
amount = 50,
time = 0.5,
minpos = { x = pos.x - 1, y = pos.y + 1, z = pos.z - 1 },
maxpos = { x = pos.x + 1, y = pos.y + 1.5, z = pos.z + 1 },
minvel = { x = -0.1, y = -0.5, z = -0.1 },
maxvel = { x = 0.1, y = -1.5, z = 0.1 },
minacc = { x = -0.1, y = -0.5, z = -0.1 },
maxacc = { x = 0.1, y = -1.5, z = 0.1 },
minexptime = 0.5,
maxexptime = 1,
minsize = 0.5,
maxsize = 1,
texture = 'x_enchanting_scroll_particle.png^[colorize:#A179E9:256',
glow = 1
}
if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then
-- new syntax, after v5.6.0
particlespawner_def = {
amount = 50,
time = 0.5,
size = {
min = 0.5,
max = 1,
},
exptime = 2,
pos = {
min = vector.new({ x = pos.x - 1.5, y = pos.y + 1, z = pos.z - 1.5 }),
max = vector.new({ x = pos.x + 1.5, y = pos.y + 1.5, z = pos.z + 1.5 }),
},
attract = {
kind = 'point',
strength = 2,
origin = vector.new({ x = pos.x, y = pos.y + 0.65, z = pos.z }),
die_on_contact = true
},
texture = {
name = 'x_enchanting_scroll_particle.png^[colorize:#A179E9:256',
alpha_tween = {
0.5, 1,
style = 'fwd',
reps = 1
}
},
glow = 1
}
end
minetest.add_particlespawner(particlespawner_def)
end end
function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_def) function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_def)
@ -561,6 +646,7 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d
if not enchantment_def.groups then if not enchantment_def.groups then
group_enchantments[enchantment_name] = enchantment_def group_enchantments[enchantment_name] = enchantment_def
else else
---@diagnostic disable-next-line: unused-local
for i, group in ipairs(enchantment_def.groups) do for i, group in ipairs(enchantment_def.groups) do
if minetest.get_item_group(tool_def.name, group) > 0 then if minetest.get_item_group(tool_def.name, group) > 0 then
group_enchantments[enchantment_name] = enchantment_def group_enchantments[enchantment_name] = enchantment_def
@ -647,6 +733,7 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d
local total_weight = 0 local total_weight = 0
-- calculate total weight -- calculate total weight
---@diagnostic disable-next-line: unused-local
for j, enchantment in ipairs(possible_enchantments) do for j, enchantment in ipairs(possible_enchantments) do
total_weight = total_weight + self.enchantment_defs[enchantment.id].weight total_weight = total_weight + self.enchantment_defs[enchantment.id].weight
end end
@ -691,11 +778,17 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d
table.remove(possible_enchantments, idx) table.remove(possible_enchantments, idx)
end end
end end
else else
local probability = (probability_level + 1) / 50 local probability = (probability_level + 1) / 50
local alreadyInTable = tableFind(final_enchantments, function(value)
return value.id == rand_ench.id
end)
if not alreadyInTable then
table.insert(final_enchantments, rand_ench) table.insert(final_enchantments, rand_ench)
end
table.remove(possible_enchantments, rand_ench_idx) table.remove(possible_enchantments, rand_ench_idx)
for idx, value in pairs(possible_enchantments) do for idx, value in pairs(possible_enchantments) do
@ -743,6 +836,39 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d
return data return data
end end
local function get_hotbar_bg(x, y)
local out = ''
for i = 0, 7, 1 do
out = out .. 'image[' .. x + i .. ',' .. y .. ';1,1;x_enchanting_gui_hb_bg.png]'
end
return out
end
local function get_list_bg(x, y)
local out = ''
for row = 0, 2, 1 do
for i = 0, 7, 1 do
out = out .. 'image[' .. x + i .. ',' .. y + row .. ';1,1;x_enchanting_gui_slot_bg.png]'
end
end
return out
end
local function get_formspec_bg(player_name)
local info = minetest.get_player_information(player_name)
local bg = 'background[5,5;1,1;x_enchanting_gui_formbg.png;true]'
if info.formspec_version > 1 then
bg = 'background9[5,5;1,1;x_enchanting_gui_formbg.png;true;10]'
end
return bg
end
function XEnchanting.get_formspec(self, pos, player_name, data) function XEnchanting.get_formspec(self, pos, player_name, data)
local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z
local inv = minetest.get_meta(pos):get_inventory() local inv = minetest.get_meta(pos):get_inventory()
@ -754,21 +880,29 @@ function XEnchanting.get_formspec(self, pos, player_name, data)
local formspec = { local formspec = {
'size[8,9]', 'size[8,9]',
'bgcolor[#080808BB;true]',
'listcolors[#FFFFFF00;#FFFFFF1A;#FFFFFF00;#30434C;#FFF]',
get_formspec_bg(player_name),
'style_type[label;font=mono,bold]',
'style[slot_1,slot_2,slot_3;font=mono,bold;textcolor=#4D413A]',
'label[0, 0;' .. S('Enchant') .. ']', 'label[0, 0;' .. S('Enchant') .. ']',
-- item
'list[nodemeta:' .. spos .. ';item;0, 2.5;1, 1;]', 'list[nodemeta:' .. spos .. ';item;0, 2.5;1, 1;]',
'image[1,2.5;1,1;x_enchanting_trade_slot.png;]', 'image[0, 2.5;1,1;x_enchanting_gui_cloth_bg.png]',
-- trade
'list[nodemeta:' .. spos .. ';trade;1, 2.5;1, 1;]', 'list[nodemeta:' .. spos .. ';trade;1, 2.5;1, 1;]',
'image[1, 2.5;1,1;x_enchanting_gui_cloth_trade_bg.png]',
-- inventories
'list[current_player;main;0, 4.85;8, 1;]', 'list[current_player;main;0, 4.85;8, 1;]',
'list[current_player;main;0, 6.08;8, 3;8]', 'list[current_player;main;0, 6.08;8, 3;8]',
'listring[nodemeta:' .. spos .. ';trade]', 'listring[nodemeta:' .. spos .. ';trade]',
'listring[current_player;main]', 'listring[current_player;main]',
'listring[nodemeta:' .. spos .. ';item]', 'listring[nodemeta:' .. spos .. ';item]',
'listring[current_player;main]' 'listring[current_player;main]',
} }
if default then formspec[#formspec + 1] = get_hotbar_bg(0, 4.85)
formspec[#formspec + 1] = default.get_hotbar_bg(0, 4.85) formspec[#formspec + 1] = get_list_bg(0, 6.08)
end
-- data -- data
if data then if data then
@ -778,17 +912,17 @@ function XEnchanting.get_formspec(self, pos, player_name, data)
if inv:get_stack('trade', 1):get_count() >= i then if inv:get_stack('trade', 1):get_count() >= i then
---@diagnostic disable-next-line: codestyle-check ---@diagnostic disable-next-line: codestyle-check
formspec[#formspec + 1] = 'image_button[2.5,' .. -0.5 + i .. ';5,1;x_enchanting_image_button.png;slot_' .. i .. ';' .. slot.descriptions.enchantments_desc_masked .. ' ' .. minetest.colorize('#FFFF00', S('level') .. ': ' .. slot.level) .. ']' formspec[#formspec + 1] = 'image_button[3.125,' .. -0.5 + i .. ';5.125,1;x_enchanting_image_button.png;slot_' .. i .. ';' .. slot.descriptions.enchantments_desc_masked .. minetest.formspec_escape(' [' .. slot.level .. ']') .. ']'
else else
---@diagnostic disable-next-line: codestyle-check ---@diagnostic disable-next-line: codestyle-check
formspec[#formspec + 1] = 'image_button[2.5,' .. -0.5 + i .. ';5,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';' .. slot.descriptions.enchantments_desc_masked .. ' ' .. minetest.colorize('#FFFF00', S('level') .. ': ' .. slot.level) .. ']' formspec[#formspec + 1] = 'image_button[3.125,' .. -0.5 + i .. ';5.125,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';' .. slot.descriptions.enchantments_desc_masked .. minetest.formspec_escape(' [' .. slot.level .. ']') .. ']'
end end
formspec[#formspec + 1] = 'image[2.5,' .. -0.5 + i .. ';1,1;x_enchanting_image_trade_' .. i .. '.png;]' formspec[#formspec + 1] = 'image[2.3,' .. -0.5 + i .. ';1,1;x_enchanting_image_trade_' .. i .. '.png;]'
else else
-- disabled buttons -- disabled buttons
---@diagnostic disable-next-line: codestyle-check ---@diagnostic disable-next-line: codestyle-check
formspec[#formspec + 1] = 'image_button[2.5,' .. -0.5 + i .. ';5,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';]' formspec[#formspec + 1] = 'image_button[3.125,' .. -0.5 + i .. ';5.125,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';]'
end end
end end
@ -797,7 +931,7 @@ function XEnchanting.get_formspec(self, pos, player_name, data)
for i = 1, 3, 1 do for i = 1, 3, 1 do
-- disabled buttons -- disabled buttons
---@diagnostic disable-next-line: codestyle-check ---@diagnostic disable-next-line: codestyle-check
formspec[#formspec + 1] = 'image_button[2.5,' .. -0.5 + i .. ';5,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';]' formspec[#formspec + 1] = 'image_button[3.125,' .. -0.5 + i .. ';5.125,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';]'
end end
model_scroll_is_open = false model_scroll_is_open = false

Binary file not shown.

Binary file not shown.

View File

@ -31,36 +31,6 @@ pipelines:
script: script:
- nvm use v17.2.0 - nvm use v17.2.0
- npm run lua-diagnostics - npm run lua-diagnostics
branches:
master:
- step:
name: Install Node Dependencies
caches:
- node-modules
- npm
- nvm
script:
- nvm install v17.2.0
- npm i -g npm@8
- npm ci
- parallel:
- step:
name: Lua Check
script:
- apt-get update
- apt-get -y install lua5.1
- apt-get -y install luarocks
- luarocks install luacheck
- luacheck .
- step:
name: Lua Diagnostics
caches:
- node-modules
- npm
- nvm
script:
- nvm use v17.2.0
- npm run lua-diagnostics
tags: tags:
"*": "*":
- step: - step:
@ -73,7 +43,7 @@ pipelines:
- nvm install v17.2.0 - nvm install v17.2.0
- npm i -g npm@8 - npm i -g npm@8
- npm ci - npm ci
- parallel: # - parallel:
- step: - step:
name: Lua Check name: Lua Check
script: script:
@ -82,15 +52,15 @@ pipelines:
- apt-get -y install luarocks - apt-get -y install luarocks
- luarocks install luacheck - luarocks install luacheck
- luacheck . - luacheck .
- step: # - step:
name: Lua Diagnostics # name: Lua Diagnostics
caches: # caches:
- node-modules # - node-modules
- npm # - npm
- nvm # - nvm
script: # script:
- nvm use v17.2.0 # - nvm use v17.2.0
- npm run lua-diagnostics # - npm run lua-diagnostics
- step: - step:
name: Deploy to ContentDB name: Deploy to ContentDB
caches: caches:

158
init.lua
View File

@ -1,5 +1,20 @@
-- X Enchanting --[[
-- by SaKeL X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to juraj.vajda@gmail.com
--]]
local path = minetest.get_modpath('x_enchanting') local path = minetest.get_modpath('x_enchanting')
local mod_start_time = minetest.get_us_time() local mod_start_time = minetest.get_us_time()
@ -7,20 +22,156 @@ local mod_start_time = minetest.get_us_time()
dofile(path .. '/api.lua') dofile(path .. '/api.lua')
dofile(path .. '/table.lua') dofile(path .. '/table.lua')
---Check if string X starts with string Y
---@param str string
---@param start string
---@return boolean
local function starts_with(str, start)
return str:sub(1, #start) == start
end
minetest.register_on_mods_loaded(function() minetest.register_on_mods_loaded(function()
-- Tools override
for name, tool_def in pairs(minetest.registered_tools) do for name, tool_def in pairs(minetest.registered_tools) do
if XEnchanting:has_tool_group(name) then if XEnchanting:has_tool_group(name) then
XEnchanting:set_tool_enchantability(tool_def) XEnchanting:set_tool_enchantability(tool_def)
end end
end end
-- Ores override - Fortune
for _, def in pairs(minetest.registered_ores) do for _, def in pairs(minetest.registered_ores) do
if not XEnchanting.registered_ores[def.ore] then if not XEnchanting.registered_ores[def.ore] then
XEnchanting.registered_ores[def.ore] = true XEnchanting.registered_ores[def.ore] = true
end end
end end
-- Entities override - Looting
for name, def in pairs(minetest.registered_entities) do
if starts_with(name, 'mobs_animal:')
or starts_with(name, 'mobs_monster:')
then
if def.on_punch and def.drops then
local prev_on_punch = def.on_punch
---@param self table
---@param puncher ObjectRef|nil
---@param time_from_last_punch number|integer|nil
---@param tool_capabilities ToolCapabilitiesDef|nil
---@param dir Vector
---@param damage number|integer
---@return boolean|nil
def.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
if not self
or not self.object
or not self.object:get_luaentity()
or not puncher
or not tool_capabilities
then
return prev_on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
end
local wield_stack = puncher:get_wielded_item()
local wield_stack_meta = wield_stack:get_meta()
local looting = wield_stack_meta:get_float('is_looting')
if looting == 0 then
return prev_on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
end
local pos = self.object:get_pos()
prev_on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
if self.health and self.health <= 0 then
local death_by_player = self.cause_of_death
and self.cause_of_death.puncher
and self.cause_of_death.puncher:is_player()
if death_by_player and pos then
for _, drop in ipairs(def.drops) do
if math.random(10, 100) / 100 < looting / (looting + 1) then
local drop_min = drop.min or 0
local drop_max = drop.max or 0
local count = math.random(drop_min, drop_max)
local stack = ItemStack({
name = drop.name,
count = count
})
local chance = math.random(1, tool_capabilities.max_drop_level)
stack:set_count(stack:get_count() * chance)
if stack:get_count() > 0 then
minetest.item_drop(stack, puncher, pos)
end
end
end
end
end
end
end
elseif starts_with(name, 'animalia:') then
if def.death_func and def.drops then
local prev_death_func = def.death_func
---@param self table
def.death_func = function(self)
local puncher = self._puncher
if not self
or not self.object
or not self.object:get_luaentity()
or not puncher
or not puncher:is_player()
or self._looting_dropped
then
return prev_death_func(self)
end
local wield_stack = puncher:get_wielded_item()
local wield_stack_meta = wield_stack:get_meta()
local looting = wield_stack_meta:get_float('is_looting')
if looting == 0 then
return prev_death_func(self)
end
local pos = self.object:get_pos()
prev_death_func(self)
local death_by_player = puncher and puncher:is_player()
if death_by_player and pos then
local tool_capabilities = wield_stack:get_tool_capabilities()
self._looting_dropped = true
for _, drop in ipairs(def.drops) do
if math.random(10, 100) / 100 < looting / (looting + 1) then
local drop_min = drop.min or 0
local drop_max = drop.max or 0
local count = math.random(drop_min, drop_max)
local stack = ItemStack({
name = drop.name,
count = count
})
local chance = math.random(1, tool_capabilities.max_drop_level)
stack:set_count(stack:get_count() * chance)
if stack:get_count() > 0 then
minetest.item_drop(stack, puncher, pos)
end
end
end
end
end
end
end
end
end) end)
---@diagnostic disable-next-line: unused-local
minetest.register_on_joinplayer(function(player, last_login) minetest.register_on_joinplayer(function(player, last_login)
XEnchanting.form_context[player:get_player_name()] = nil XEnchanting.form_context[player:get_player_name()] = nil
@ -29,6 +180,7 @@ minetest.register_on_joinplayer(function(player, last_login)
end end
end) end)
---@diagnostic disable-next-line: unused-local
minetest.register_on_leaveplayer(function(player, timed_out) minetest.register_on_leaveplayer(function(player, timed_out)
XEnchanting.form_context[player:get_player_name()] = nil XEnchanting.form_context[player:get_player_name()] = nil
end) end)
@ -94,12 +246,12 @@ function minetest.handle_node_drops(pos, drops, digger)
return old_handle_node_drops(pos, drops, digger) return old_handle_node_drops(pos, drops, digger)
end end
---@diagnostic disable-next-line: unused-local
minetest.register_on_player_hpchange(function(player, hp_change, reason) minetest.register_on_player_hpchange(function(player, hp_change, reason)
-- Curse of Vanishing -- Curse of Vanishing
if (player:get_hp() + hp_change) <= 0 then if (player:get_hp() + hp_change) <= 0 then
-- Going to die -- Going to die
local player_inv = player:get_inventory() --[[@as InvRef]] local player_inv = player:get_inventory() --[[@as InvRef]]
local player_inventory_lists = { 'main', 'craft' } local player_inventory_lists = { 'main', 'craft' }
for _, list_name in ipairs(player_inventory_lists) do for _, list_name in ipairs(player_inventory_lists) do

View File

@ -1,14 +1,17 @@
# textdomain: x_enchanting # textdomain: x_enchanting
Sharpness= Sharpness=
Looting=
Fortune= Fortune=
Unbreaking= Unbreaking=
Efficiency= Efficiency=
Silk Touch= Silk Touch=
Curse of Vanishing= Curse of Vanishing=
Knockback= Knockback=
Power=
Punch=
Infinity=
Enchanted= Enchanted=
Enchant= Enchant=
level=
Enchanting Table= Enchanting Table=
owned by= owned by=
Scroll of Enchantments= Scroll of Enchantments=

View File

@ -1,14 +1,17 @@
# textdomain: x_enchanting # textdomain: x_enchanting
Sharpness=Ostrosť Sharpness=Ostrosť
Looting=
Fortune=Šťastie Fortune=Šťastie
Unbreaking=Nelámavosť Unbreaking=Nelámavosť
Efficiency=Výkonnosť Efficiency=Výkonnosť
Silk Touch=Hodvábny dotyk Silk Touch=Hodvábny dotyk
Curse of Vanishing=Kliatba zmiznutia Curse of Vanishing=Kliatba zmiznutia
Knockback=Spätný úder Knockback=Spätný úder
Power=
Punch=
Infinity=
Enchanted=Očarený Enchanted=Očarený
Enchant=Očarovať Enchant=Očarovať
level=level
Enchanting Table=Čarovný stôl Enchanting Table=Čarovný stôl
owned by=vlastník owned by=vlastník
Scroll of Enchantments=Čarovný Zvitok Scroll of Enchantments=Čarovný Zvitok

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 385 KiB

View File

@ -1,3 +1,21 @@
/**
* Deploy code to CDB
* Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to juraj.vajda@gmail.com
*/
import fetch from 'node-fetch' import fetch from 'node-fetch'
import yargs from 'yargs/yargs' import yargs from 'yargs/yargs'
import {hideBin} from 'yargs/helpers' import {hideBin} from 'yargs/helpers'

View File

@ -1,3 +1,21 @@
/**
* Run LUA diagnostics in continuous integration
* Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to juraj.vajda@gmail.com
*/
import * as path from 'node:path' import * as path from 'node:path'
import * as fs from 'node:fs' import * as fs from 'node:fs'
import {exec} from 'node:child_process' import {exec} from 'node:child_process'

View File

@ -1,3 +1,22 @@
--[[
X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to juraj.vajda@gmail.com
--]]
---@diagnostic disable-next-line
screwdriver = minetest.global_exists('screwdriver') and screwdriver --[[@as MtgScrewdriver]] screwdriver = minetest.global_exists('screwdriver') and screwdriver --[[@as MtgScrewdriver]]
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
@ -59,6 +78,7 @@ minetest.register_node('x_enchanting:table', {
---@param placer ObjectRef | nil ---@param placer ObjectRef | nil
---@param itemstack ItemStack ---@param itemstack ItemStack
---@param pointed_thing PointedThingDef ---@param pointed_thing PointedThingDef
---@diagnostic disable-next-line: unused-local
after_place_node = function(pos, placer, itemstack, pointed_thing) after_place_node = function(pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
@ -79,6 +99,7 @@ minetest.register_node('x_enchanting:table', {
---@param clicker ObjectRef ---@param clicker ObjectRef
---@param itemstack ItemStack ---@param itemstack ItemStack
---@param pointed_thing? PointedThingDef ---@param pointed_thing? PointedThingDef
---@diagnostic disable-next-line: unused-local
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local p_name = clicker:get_player_name() local p_name = clicker:get_player_name()
@ -123,6 +144,7 @@ minetest.register_node('x_enchanting:table', {
---@param pos Vector ---@param pos Vector
---@param intensity? number ---@param intensity? number
---@return table | nil ---@return table | nil
---@diagnostic disable-next-line: unused-local
on_blast = function(pos, intensity) on_blast = function(pos, intensity)
if minetest.is_protected(pos, '') then if minetest.is_protected(pos, '') then
return return
@ -159,11 +181,13 @@ minetest.register_node('x_enchanting:table', {
and inv:is_empty('trade') and inv:is_empty('trade')
and not minetest.is_protected(pos, player:get_player_name()) and not minetest.is_protected(pos, player:get_player_name())
end, end,
---@diagnostic disable-next-line: unused-local
on_rotate = function(pos, node, user, mode, new_param2) on_rotate = function(pos, node, user, mode, new_param2)
return false return false
end, end,
---@param pos Vector ---@param pos Vector
---@param elapsed number ---@param elapsed number
---@diagnostic disable-next-line: unused-local
on_timer = function(pos, elapsed) on_timer = function(pos, elapsed)
-- entity -- entity
local table_scroll = minetest.get_objects_inside_radius(pos, 0.9) local table_scroll = minetest.get_objects_inside_radius(pos, 0.9)
@ -234,6 +258,7 @@ minetest.register_node('x_enchanting:table', {
end end
-- symbol particles -- symbol particles
---@diagnostic disable-next-line: unused-local
for i = 1, 10, 1 do for i = 1, 10, 1 do
local pos_random = bookshelfs[math.random(1, #bookshelfs)] local pos_random = bookshelfs[math.random(1, #bookshelfs)]
local x = pos.x - pos_random.x local x = pos.x - pos_random.x
@ -275,6 +300,7 @@ minetest.register_node('x_enchanting:table', {
---@param index number ---@param index number
---@param stack ItemStack ---@param stack ItemStack
---@param player ObjectRef ---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
allow_metadata_inventory_put = function(pos, listname, index, stack, player) allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local st_meta = stack:get_meta() local st_meta = stack:get_meta()
local st_name = stack:get_name() local st_name = stack:get_name()
@ -302,6 +328,7 @@ minetest.register_node('x_enchanting:table', {
---@param index number ---@param index number
---@param stack ItemStack ---@param stack ItemStack
---@param player ObjectRef ---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
allow_metadata_inventory_take = function(pos, listname, index, stack, player) allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local st_name = stack:get_name() local st_name = stack:get_name()
@ -325,6 +352,7 @@ minetest.register_node('x_enchanting:table', {
---@param to_index number ---@param to_index number
---@param count number ---@param count number
---@param player ObjectRef ---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0 return 0
end, end,
@ -333,12 +361,16 @@ minetest.register_node('x_enchanting:table', {
---@param index number ---@param index number
---@param stack ItemStack ---@param stack ItemStack
---@param player ObjectRef ---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
on_metadata_inventory_put = function(pos, listname, index, stack, player) on_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local p_name = player:get_player_name() local p_name = player:get_player_name()
local inv = meta:get_inventory() local inv = meta:get_inventory()
local item_stack = inv:get_stack('item', 1)
local item_stack_meta = item_stack:get_meta()
local is_enchanted = item_stack_meta:get_int('is_enchanted')
if not inv:is_empty('item') then if not inv:is_empty('item') and is_enchanted == 0 then
-- bookshelfs -- bookshelfs
local bookshelfs = minetest.find_nodes_in_area( local bookshelfs = minetest.find_nodes_in_area(
{ x = pos.x - 2, y = pos.y, z = pos.z - 2 }, { x = pos.x - 2, y = pos.y, z = pos.z - 2 },
@ -346,7 +378,6 @@ minetest.register_node('x_enchanting:table', {
{ 'default:bookshelf', 'group:bookshelf' } { 'default:bookshelf', 'group:bookshelf' }
) )
local item_stack = inv:get_stack('item', 1)
local data = XEnchanting:get_enchantment_data( local data = XEnchanting:get_enchantment_data(
player, player,
#bookshelfs, #bookshelfs,
@ -366,12 +397,16 @@ minetest.register_node('x_enchanting:table', {
---@param index number ---@param index number
---@param stack ItemStack ---@param stack ItemStack
---@param player ObjectRef ---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
on_metadata_inventory_take = function(pos, listname, index, stack, player) on_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local p_name = player:get_player_name() local p_name = player:get_player_name()
local inv = meta:get_inventory() local inv = meta:get_inventory()
local item_stack = inv:get_stack('item', 1)
local item_stack_meta = item_stack:get_meta()
local is_enchanted = item_stack_meta:get_int('is_enchanted')
if not inv:is_empty('item') then if not inv:is_empty('item') and is_enchanted == 0 then
-- bookshelfs -- bookshelfs
local bookshelfs = minetest.find_nodes_in_area( local bookshelfs = minetest.find_nodes_in_area(
{ x = pos.x - 2, y = pos.y, z = pos.z - 2 }, { x = pos.x - 2, y = pos.y, z = pos.z - 2 },
@ -379,7 +414,6 @@ minetest.register_node('x_enchanting:table', {
{ 'default:bookshelf', 'group:bookshelf' } { 'default:bookshelf', 'group:bookshelf' }
) )
local item_stack = inv:get_stack('item', 1)
local data = XEnchanting:get_enchantment_data( local data = XEnchanting:get_enchantment_data(
player, player,
#bookshelfs, #bookshelfs,
@ -399,6 +433,7 @@ minetest.register_node('x_enchanting:table', {
---@param formname string ---@param formname string
---@param fields table ---@param fields table
---@param sender ObjectRef ---@param sender ObjectRef
---@diagnostic disable-next-line: unused-local
on_receive_fields = function(pos, formname, fields, sender) on_receive_fields = function(pos, formname, fields, sender)
local p_name = sender:get_player_name() local p_name = sender:get_player_name()
@ -477,12 +512,14 @@ minetest.register_entity('x_enchanting:table_scroll', {
}, },
---@param self table ---@param self table
---@param killer ObjectRef ---@param killer ObjectRef
---@diagnostic disable-next-line: unused-local
on_death = function(self, killer) on_death = function(self, killer)
self.object:remove() self.object:remove()
end, end,
---@param self table ---@param self table
---@param staticdata StringAbstract ---@param staticdata StringAbstract
---@param dtime_s number ---@param dtime_s number
---@diagnostic disable-next-line: unused-local
on_activate = function(self, staticdata, dtime_s) on_activate = function(self, staticdata, dtime_s)
self._scroll_closed = true self._scroll_closed = true
self._tablechecktimer = 5 self._tablechecktimer = 5
@ -496,6 +533,7 @@ minetest.register_entity('x_enchanting:table_scroll', {
---@param self table ---@param self table
---@param dtime number ---@param dtime number
---@param moveresult? table ---@param moveresult? table
---@diagnostic disable-next-line: unused-local
on_step = function(self, dtime, moveresult) on_step = function(self, dtime, moveresult)
local pos = self.object:get_pos() local pos = self.object:get_pos()
@ -524,6 +562,7 @@ minetest.register_entity('x_enchanting:table_scroll', {
local found_player = false local found_player = false
if #objects > 0 then if #objects > 0 then
---@diagnostic disable-next-line: unused-local
for i, obj in ipairs(objects) do for i, obj in ipairs(objects) do
if obj:is_player() and obj:get_pos() then if obj:is_player() and obj:get_pos() then
-- player -- player
@ -531,6 +570,7 @@ minetest.register_entity('x_enchanting:table_scroll', {
local distance = vector.distance(pos, obj:get_pos()) local distance = vector.distance(pos, obj:get_pos())
if distance < shortest_distance then if distance < shortest_distance then
shortest_distance = distance
self._player = obj self._player = obj
end end
end end
@ -584,6 +624,7 @@ minetest.register_entity('x_enchanting:table_scroll', {
---@param dir Vector ---@param dir Vector
---@param damage number ---@param damage number
---@return boolean | nil ---@return boolean | nil
---@diagnostic disable-next-line: unused-local
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
return true return true
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 B

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 B

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 B

View File

@ -14,3 +14,4 @@
---@field on_detach_child fun(self: table, child: ObjectRef): nil Function receive a "luaentity" table as `self`. `child`: an `ObjectRef` of the child that detaches ---@field on_detach_child fun(self: table, child: ObjectRef): nil Function receive a "luaentity" table as `self`. `child`: an `ObjectRef` of the child that detaches
---@field on_detach fun(self: table, parent: ObjectRef|nil): nil Function receive a "luaentity" table as `self`. `parent`: an `ObjectRef` (can be `nil`) from where it got detached. This happens before the parent object is removed from the world. ---@field on_detach fun(self: table, parent: ObjectRef|nil): nil Function receive a "luaentity" table as `self`. `parent`: an `ObjectRef` (can be `nil`) from where it got detached. This happens before the parent object is removed from the world.
---@field get_staticdata fun(self: table) Function receive a "luaentity" table as `self`. Should return a string that will be passed to `on_activate` when the object is instantiated the next time. ---@field get_staticdata fun(self: table) Function receive a "luaentity" table as `self`. Should return a string that will be passed to `on_activate` when the object is instantiated the next time.
---@field drops table Custom for mob drops

View File

@ -16,6 +16,7 @@
---@field get_node fun(pos: Vector): NodeDef Returns the node at the given position as table in the format `{name="node_name", param1=0, param2=0}`, returns `{name="ignore", param1=0, param2=0}` for unloaded areas. ---@field get_node fun(pos: Vector): NodeDef Returns the node at the given position as table in the format `{name="node_name", param1=0, param2=0}`, returns `{name="ignore", param1=0, param2=0}` for unloaded areas.
---@field registered_nodes table<string, NodeDef|ItemDef> Map of registered node definitions, indexed by name ---@field registered_nodes table<string, NodeDef|ItemDef> Map of registered node definitions, indexed by name
---@field registered_ores table<string, table> Map of registered ore definitions, indexed by name ---@field registered_ores table<string, table> Map of registered ore definitions, indexed by name
---@field registered_craftitems table<string, table> Map of registered craft items, indexed by name
---@field after fun(time: number|integer, func: fun(...), ...): JobTable Call the function `func` after `time` seconds, may be fractional. Optional: Variable number of arguments that are passed to `func`. ---@field after fun(time: number|integer, func: fun(...), ...): JobTable Call the function `func` after `time` seconds, may be fractional. Optional: Variable number of arguments that are passed to `func`.
---@field sound_play fun(spec: SimpleSoundSpec|string, parameters: SoundParamDef, ephemeral?: boolean): any Returns a `handle`. Ephemeral sounds will not return a handle and can't be stopped or faded. It is recommend to use this for short sounds that happen in response to player actions (e.g. door closing). ---@field sound_play fun(spec: SimpleSoundSpec|string, parameters: SoundParamDef, ephemeral?: boolean): any Returns a `handle`. Ephemeral sounds will not return a handle and can't be stopped or faded. It is recommend to use this for short sounds that happen in response to player actions (e.g. door closing).
---@field add_particlespawner fun(particlespawner_definition: ParticlespawnerDef): number|integer Add a `ParticleSpawner`, an object that spawns an amount of particles over `time` seconds. Returns an `id`, and -1 if adding didn't succeed. ---@field add_particlespawner fun(particlespawner_definition: ParticlespawnerDef): number|integer Add a `ParticleSpawner`, an object that spawns an amount of particles over `time` seconds. Returns an `id`, and -1 if adding didn't succeed.
@ -88,11 +89,12 @@
---@field place_node fun(pos: Vector, node: SetNodeTable): nil Place node with the same effects that a player would cause ---@field place_node fun(pos: Vector, node: SetNodeTable): nil Place node with the same effects that a player would cause
---@field add_particle fun(def: ParticleDef): nil ---@field add_particle fun(def: ParticleDef): nil
---@field registered_tools table<string, ItemDef> Map of registered tool definitions, indexed by name ---@field registered_tools table<string, ItemDef> Map of registered tool definitions, indexed by name
---@field registered_entities table<string, ObjectRef> Map of registered entity definitions, indexed by name ---@field registered_entities table<string, EntityDef> Map of registered entity definitions, indexed by name
---@field has_feature fun(args: table<string, boolean> | string): boolean | table returns `boolean, missing_features`, `arg`: string or table in format `{foo=true, bar=true}`, `missing_features`: `{foo=true, bar=true}` ---@field has_feature fun(args: table<string, boolean> | string): boolean | table returns `boolean, missing_features`, `arg`: string or table in format `{foo=true, bar=true}`, `missing_features`: `{foo=true, bar=true}`
---@field handle_node_drops fun(pos: Vector, drops: string[], digger: ObjectRef) `drops`: list of itemstrings. Handles drops from nodes after digging: Default action is to put them into digger's inventory. Can be overridden to get different functionality (e.g. dropping items on ground) ---@field handle_node_drops fun(pos: Vector, drops: string[], digger: ObjectRef) `drops`: list of itemstrings. Handles drops from nodes after digging: Default action is to put them into digger's inventory. Can be overridden to get different functionality (e.g. dropping items on ground)
---@field register_on_dieplayer fun(func: fun(player: ObjectRef, reason?: string)): nil Called when a player dies. `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange ---@field register_on_dieplayer fun(func: fun(player: ObjectRef, reason?: string)): nil Called when a player dies. `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange
---@field register_on_player_hpchange fun(func: fun(player, hp_change, reason), modifier): number Called when the player gets damaged or healed. `player`: ObjectRef of the player. `hp_change`: the amount of change. Negative when it is damage.. `reason`: a PlayerHPChangeReason table.. The `type` field will have one of the following values: `set_hp`: A mod or the engine called `set_hp` without giving a type - use this for custom damage types.. `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. `fall`, `node_damage`: `damage_per_second` from a neighbouring node. `reason.node` will hold the node name or nil. `drown` `respawn`. Any of the above types may have additional fields from mods. `reason.from` will be `mod` or `engine`. `modifier`: when true, the function should return the actual `hp_change`. Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. Modifiers can return true as a second argument to stop the execution of further functions. Non-modifiers receive the final HP change calculated by the modifiers. ---@field register_on_player_hpchange fun(func: fun(player, hp_change, reason), modifier): number Called when the player gets damaged or healed. `player`: ObjectRef of the player. `hp_change`: the amount of change. Negative when it is damage.. `reason`: a PlayerHPChangeReason table.. The `type` field will have one of the following values: `set_hp`: A mod or the engine called `set_hp` without giving a type - use this for custom damage types.. `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. `fall`, `node_damage`: `damage_per_second` from a neighbouring node. `reason.node` will hold the node name or nil. `drown` `respawn`. Any of the above types may have additional fields from mods. `reason.from` will be `mod` or `engine`. `modifier`: when true, the function should return the actual `hp_change`. Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. Modifiers can return true as a second argument to stop the execution of further functions. Non-modifiers receive the final HP change calculated by the modifiers.
---@field get_player_information fun(player_name: string): table Table containing information about a player
---Minetest settings ---Minetest settings
---@class MinetestSettings ---@class MinetestSettings

View File

@ -45,6 +45,7 @@
---@field get_rotation fun(self: ObjectRef): Vector returns the rotation, a vector (radians) ---@field get_rotation fun(self: ObjectRef): Vector returns the rotation, a vector (radians)
---@field get_attach fun(self: ObjectRef): any Returns parent, bone, position, rotation, forced_visible, or nil if it isn't attached. ---@field get_attach fun(self: ObjectRef): any Returns parent, bone, position, rotation, forced_visible, or nil if it isn't attached.
---@field set_attach fun(self: ObjectRef, parent: ObjectRef, bone?: string, position?: Vector, rotation?: Vector, forced_visible?: boolean): any Returns parent, bone, position, rotation, forced_visible, or nil if it isn't attached. ---@field set_attach fun(self: ObjectRef, parent: ObjectRef, bone?: string, position?: Vector, rotation?: Vector, forced_visible?: boolean): any Returns parent, bone, position, rotation, forced_visible, or nil if it isn't attached.
---@field drops table Custom for mob drops
---`ObjectRef` armor groups ---`ObjectRef` armor groups
---@class ObjectRefArmorGroups ---@class ObjectRefArmorGroups

View File

@ -15,6 +15,7 @@
---@field scroll_animations table<string, table> Parameters for `ObjectRef` `set_animation` method ---@field scroll_animations table<string, table> Parameters for `ObjectRef` `set_animation` method
---@field player_seeds table<string, number | integer> ---@field player_seeds table<string, number | integer>
---@field registered_ores table<string, boolean> Table with registered ores, `key` ore name ---@field registered_ores table<string, boolean> Table with registered ores, `key` ore name
---@field settings {["x_enchanting_small_formspec"]: boolean}
---Enchantment definition ---Enchantment definition
@ -49,5 +50,5 @@
---@class EnchantmentDataSlot ---@class EnchantmentDataSlot
---@field level number ---@field level number
---@field final_enchantments Enchantment[] ---@field final_enchantments Enchantment[]
---@field tool_cap_data ToolCapabilitiesDef ---@field tool_cap_data ToolCapabilitiesDef | nil
---@field descriptions {["enchantments_desc"]: string, ["enchantments_desc_masked"]: string } ---@field descriptions {["enchantments_desc"]: string, ["enchantments_desc_masked"]: string }