Compare commits

..

3 Commits

Author SHA1 Message Date
Juraj Vajda
eee56f7f0d add writing table 2023-12-12 08:42:25 -05:00
Juraj Vajda
478de78b48 Merge branch 'master' into feature/add-writing-table 2023-12-07 17:41:57 -05:00
Juraj Vajda
1af9cd2755 Add writing table - initial commit 2022-11-28 16:01:50 -05:00
52 changed files with 982 additions and 1616 deletions

View File

@ -13,6 +13,5 @@
"media_license": "CC-BY-SA-4.0",
"repo": "https://bitbucket.org/minetest_gamers/x_enchanting/src/master/",
"issue_tracker": "https://bitbucket.org/minetest_gamers/x_enchanting/issues?status=new&status=open",
"video_url": "https://youtu.be/JXF-GrQ9Uxs?si=dsgxDMXtm90ovE3D",
"forums": 28861
}

View File

@ -3,26 +3,27 @@ allow_defined_top = true
max_line_length = false
exclude_files = {
"./scripts",
"./bin",
"./logs",
"./node_modules",
"./sounds",
"./textures",
"./models",
"./docs",
"./locale",
"./types",
'./scripts',
'./bin',
'./logs',
'./node_modules',
'./sounds',
'./textures',
'./models',
'./docs',
'./locale',
'./types',
}
globals = {
"core",
"XEnchanting"
'minetest',
'XEnchanting'
}
read_globals = {
"DIR_DELIM", "INIT",
"core",
"dump", "dump2",
"Raycast",

View File

@ -453,104 +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
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
### Textures
**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_2.png
- x_enchanting_symbol_3.png
- x_enchanting_symbol_4.png
- x_enchanting_symbol_5.png
- x_enchanting_symbol_6.png
- x_enchanting_symbol_7.png
- x_enchanting_symbol_8.png
- x_enchanting_symbol_9.png
- x_enchanting_symbol_10.png
- x_enchanting_symbol_11.png
- x_enchanting_symbol_12.png
- x_enchanting_symbol_13.png
- x_enchanting_symbol_14.png
- x_enchanting_symbol_15.png
- x_enchanting_symbol_16.png
- x_enchanting_symbol_17.png
- x_enchanting_symbol_18.png
- x_enchanting_symbol_19.png
- x_enchanting_symbol_20.png
- x_enchanting_symbol_21.png
- x_enchanting_symbol_22.png
- x_enchanting_symbol_23.png
- x_enchanting_symbol_24.png
- x_enchanting_symbol_25.png
- x_enchanting_symbol_26.png
**CC-BY-SA-4.0, by SaKeL**
- x_enchanting_image_button_disabled.png
- x_enchanting_image_button.png
- x_enchanting_image_trade_1.png -- Derived from a texture by VanessaE (CC BY-SA 3.0)
- x_enchanting_image_trade_2.png -- Derived from a texture by VanessaE (CC BY-SA 3.0)
- x_enchanting_image_trade_3.png -- Derived from a texture by VanessaE (CC BY-SA 3.0)
- x_enchanting_scroll_handles_mesh.png -- Derived from a textures by paramat (CC BY-SA 3.0) and 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_table.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
**CC-BY-SA-4.0, by SaKeL**
- x_enchanting_scroll.b3d
- x_enchanting_table.obj
### Sounds
**CC-BY-3.0, Kostas17**, https://freesound.org
- x_enchanting_enchant.ogg
**CC0-1.0, Zeinel**, https://freesound.org
- x_enchanting_scroll.1.ogg
- x_enchanting_scroll.2.ogg
- x_enchanting_scroll.3.ogg
- x_enchanting_scroll.4.ogg
- x_enchanting_scroll.5.ogg
- x_enchanting_scroll.6.ogg
- x_enchanting_scroll.7.ogg
- x_enchanting_scroll.8.ogg
- x_enchanting_scroll.9.ogg
**CC0-1.0, by Fission9**, https://freesound.org
- x_enchanting_wood_footstep.1.ogg
- x_enchanting_wood_footstep.2.ogg
- x_enchanting_wood_footstep.3.ogg
- x_enchanting_wood_footstep.4.ogg
- x_enchanting_wood_footstep.5.ogg
- x_enchanting_wood_footstep.6.ogg
**CC0-1.0, by igroglaz**, https://freesound.org
- x_enchanting_wood_hit.1.ogg
- x_enchanting_wood_hit.2.ogg
- x_enchanting_wood_hit.3.ogg
- x_enchanting_wood_hit.4.ogg
- x_enchanting_wood_hit.5.ogg
- x_enchanting_wood_hit.6.ogg
**CC-BY-4.0, by RICHERlandTV**, https://freesound.org
- x_enchanting_wood_place.1.ogg
- x_enchanting_wood_place.2.ogg
- x_enchanting_wood_place.3.ogg
**CC-BY-4.0, by tim.kahn**, https://freesound.org/people/tim.kahn/sounds/35829/
- x_enchanting_disenchant.ogg

View File

@ -17,8 +17,6 @@ Adds Enchanting Mechanics and API.
* enchanted items have detailed enchantments description/short description
* mesh node model
* mesh entity model and animations
* tool texture will have enchanted glint
* adds grind stone to remove enchantments (excluding curses)
## How To
@ -185,3 +183,80 @@ end
### Code
GNU Lesser General Public License v2.1 or later (see included LICENSE file)
### Textures
**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_2.png
- x_enchanting_symbol_3.png
- x_enchanting_symbol_4.png
- x_enchanting_symbol_5.png
- x_enchanting_symbol_6.png
- x_enchanting_symbol_7.png
- x_enchanting_symbol_8.png
- x_enchanting_symbol_9.png
- x_enchanting_symbol_10.png
- x_enchanting_symbol_11.png
- x_enchanting_symbol_12.png
- x_enchanting_symbol_13.png
- x_enchanting_symbol_14.png
- x_enchanting_symbol_15.png
- x_enchanting_symbol_16.png
- x_enchanting_symbol_17.png
- x_enchanting_symbol_18.png
- x_enchanting_symbol_19.png
- x_enchanting_symbol_20.png
- x_enchanting_symbol_21.png
- x_enchanting_symbol_22.png
- x_enchanting_symbol_23.png
- x_enchanting_symbol_24.png
- x_enchanting_symbol_25.png
- x_enchanting_symbol_26.png
**CC-BY-SA-4.0, by SaKeL**
- x_enchanting_image_button_disabled.png
- x_enchanting_image_button.png
- x_enchanting_image_trade_1.png -- Derived from a texture by VanessaE (CC BY-SA 3.0)
- x_enchanting_image_trade_2.png -- Derived from a texture by VanessaE (CC BY-SA 3.0)
- x_enchanting_image_trade_3.png -- Derived from a texture by VanessaE (CC BY-SA 3.0)
- x_enchanting_scroll_handles_mesh.png -- Derived from a textures by paramat (CC BY-SA 3.0) and 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_table.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
**CC-BY-SA-4.0, by SaKeL**
- x_enchanting_scroll.b3d
- x_enchanting_table.obj
### Sounds
**CC-BY-3.0, Kostas17**, https://freesound.org
- x_enchanting_enchant.ogg
**CC0-1.0, Zeinel**, https://freesound.org
- x_enchanting_scroll.1.ogg
- x_enchanting_scroll.2.ogg
- x_enchanting_scroll.3.ogg
- x_enchanting_scroll.4.ogg
- x_enchanting_scroll.5.ogg
- x_enchanting_scroll.6.ogg
- x_enchanting_scroll.7.ogg
- x_enchanting_scroll.8.ogg
- x_enchanting_scroll.9.ogg
## Installation
see: https://wiki.minetest.net/Installing_Mods

582
api.lua
View File

@ -1,6 +1,6 @@
--[[
X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2025 SaKeL
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
@ -16,7 +16,7 @@
License along with this library; if not, write to juraj.vajda@gmail.com
--]]
local S = core.get_translator(core.get_current_modname())
local S = minetest.get_translator(minetest.get_current_modname())
---@type XEnchanting
XEnchanting = {
@ -80,8 +80,12 @@ XEnchanting = {
},
weight = 10,
groups = {
'sword'
}
'sword',
'book',
'scroll'
},
multiplier_from_scroll = 1,
multiplier_from_item = 1
},
looting = {
name = S('Looting'),
@ -99,8 +103,12 @@ XEnchanting = {
},
weight = 2,
groups = {
'sword'
}
'sword',
'book',
'scroll'
},
multiplier_from_scroll = 2,
multiplier_from_item = 4
},
fortune = {
name = S('Fortune'),
@ -120,9 +128,13 @@ XEnchanting = {
groups = {
'pickaxe',
'shovel',
'axe'
'axe',
'book',
'scroll'
},
incompatible = { 'silk_touch' }
incompatible = { 'silk_touch' },
multiplier_from_scroll = 2,
multiplier_from_item = 4
},
unbreaking = {
name = S('Unbreaking'),
@ -140,7 +152,9 @@ XEnchanting = {
},
weight = 5,
-- all applicable
groups = nil
groups = nil,
multiplier_from_scroll = 1,
multiplier_from_item = 2
},
efficiency = {
name = S('Efficiency'),
@ -150,7 +164,7 @@ XEnchanting = {
[2] = { 11, 61 },
[3] = { 21, 71 },
[4] = { 31, 81 },
[5] = { 41, 91 },
-- [5] = { 41, 91 },
},
-- level definition, `level = percentage increase`
level_def = {
@ -158,14 +172,18 @@ XEnchanting = {
[2] = 30,
[3] = 35,
[4] = 40,
[5] = 45,
-- [5] = 45,
},
weight = 10,
groups = {
'pickaxe',
'shovel',
'axe'
}
'axe',
'book',
'scroll'
},
multiplier_from_scroll = 1,
multiplier_from_item = 1
},
silk_touch = {
name = S('Silk Touch'),
@ -180,9 +198,13 @@ XEnchanting = {
groups = {
'pickaxe',
'shovel',
'axe'
'axe',
'book',
'scroll'
},
incompatible = { 'fortune' }
incompatible = { 'fortune' },
multiplier_from_scroll = 4,
multiplier_from_item = 8
},
curse_of_vanishing = {
name = S('Curse of Vanishing'),
@ -196,7 +218,8 @@ XEnchanting = {
secondary = true,
-- all applicable
groups = nil,
cursed = true
multiplier_from_scroll = 4,
multiplier_from_item = 8
},
knockback = {
name = S('Knockback'),
@ -211,8 +234,12 @@ XEnchanting = {
},
weight = 5,
groups = {
'sword'
}
'sword',
'book',
'scroll'
},
multiplier_from_scroll = 1,
multiplier_from_item = 2
},
power = {
-- Increases arrow damage.
@ -235,8 +262,12 @@ XEnchanting = {
},
weight = 10,
groups = {
'bow'
}
'bow',
'book',
'scroll'
},
multiplier_from_scroll = 1,
multiplier_from_item = 1
},
punch = {
-- Increases arrow knockback.
@ -253,8 +284,12 @@ XEnchanting = {
},
weight = 2,
groups = {
'bow'
}
'bow',
'book',
'scroll'
},
multiplier_from_scroll = 2,
multiplier_from_item = 4
},
infinity = {
-- Prevents regular arrows from being consumed when shot.
@ -271,8 +306,12 @@ XEnchanting = {
weight = 1,
secondary = true,
groups = {
'bow'
}
'bow',
'book',
'scroll'
},
multiplier_from_scroll = 4,
multiplier_from_item = 8
},
},
form_context = {},
@ -320,23 +359,25 @@ end
---@diagnostic disable-next-line: unused-local
function XEnchanting.has_tool_group(self, name)
if core.get_item_group(name, 'pickaxe') > 0 then
if minetest.get_item_group(name, 'pickaxe') > 0 then
return 'pickaxe'
elseif core.get_item_group(name, 'shovel') > 0 then
elseif minetest.get_item_group(name, 'shovel') > 0 then
return 'shovel'
elseif core.get_item_group(name, 'axe') > 0 then
elseif minetest.get_item_group(name, 'axe') > 0 then
return 'axe'
elseif core.get_item_group(name, 'sword') > 0 then
elseif minetest.get_item_group(name, 'sword') > 0 then
return 'sword'
elseif core.get_item_group(name, 'bow') > 0 then
elseif minetest.get_item_group(name, 'bow') > 0 then
return 'bow'
elseif minetest.get_item_group(name, 'book') > 0 then
return 'book'
end
return false
end
function XEnchanting.set_tool_enchantability(self, tool_def)
if core.get_item_group(tool_def.name, 'enchantability') > 0 then
function XEnchanting.set_enchantability(self, tool_def)
if minetest.get_item_group(tool_def.name, 'enchantability') > 0 then
-- enchantability is already set, we dont need to override the item
return
end
@ -347,7 +388,7 @@ function XEnchanting.set_tool_enchantability(self, tool_def)
_enchantability = self.tools_enchantability[tool_def.name]
end
core.override_item(tool_def.name, {
minetest.override_item(tool_def.name, {
groups = mergeTables(tool_def.groups, { enchantability = _enchantability })
})
end
@ -506,7 +547,7 @@ function XEnchanting.get_enchanted_descriptions(self, enchantments)
end
end
enchantments_desc = '\n' .. core.colorize('#AE81FF', S('Enchanted'))
enchantments_desc = '\n' .. minetest.colorize('#AE81FF', S('Enchanted'))
.. '\n' .. table.concat(enchantments_desc, '\n')
enchantments_desc_masked = table.concat(enchantments_desc_masked, '') .. '..?'
@ -516,25 +557,32 @@ function XEnchanting.get_enchanted_descriptions(self, enchantments)
}
end
function XEnchanting.get_glint_texture_modifier(self, image)
return image .. '^((' .. image .. '^[contrast:127:127)^[mask:x_enchanting_glint.png^[opacity:80)'
end
function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name)
local data = self.form_context[player_name].data
if not data then
minetest.log('warning', '[set_enchanted_tool] no data from form context found.')
return
end
local tool_def = minetest.registered_tools[itemstack:get_name()]
or minetest.registered_craftitems[itemstack:get_name()]
if minetest.get_item_group(tool_def.name, 'book') > 0 then
itemstack = ItemStack({ name = 'x_enchanting:scroll_item' })
end
local capabilities = data.slots[level].tool_cap_data
local description = data.slots[level].descriptions.enchantments_desc
local final_enchantments = data.slots[level].final_enchantments
local inv = core.get_meta(pos):get_inventory()
local tool_def = core.registered_tools[itemstack:get_name()]
local node_meta = core.get_meta(pos)
local inv = minetest.get_meta(pos):get_inventory()
local node_meta = minetest.get_meta(pos)
if not tool_def then
minetest.log(
'warning',
'[set_enchanted_tool] no tool definition found in registered_tools/registered_craftitems.'
)
return
end
@ -551,11 +599,18 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
}
end
stack_meta:set_tool_capabilities(capabilities)
if minetest.get_item_group(tool_def.name, 'book') == 0 then
for i, enchantment in ipairs(final_enchantments) do
stack_meta:set_float('is_' .. enchantment.id, enchantment.value)
end
stack_meta:set_tool_capabilities(capabilities)
end
stack_meta:set_string('description', itemstack:get_description() .. '\n' .. description)
stack_meta:set_string('short_description', S('Enchanted') .. ' ' .. itemstack:get_short_description())
stack_meta:set_int('is_enchanted', 1)
stack_meta:set_string('x_enchanting', core.serialize(final_enchantments_meta))
stack_meta:set_string('x_enchanting', minetest.serialize(final_enchantments))
if tool_def and tool_def.inventory_image and tool_def.inventory_image ~= '' then
stack_meta:set_string('inventory_image', tool_def.inventory_image .. '^((' .. tool_def.inventory_image .. '^[contrast:127:127)^[mask:x_enchanting_glint.png^[opacity:80)')
@ -575,6 +630,7 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
inv:set_stack('item', 1, itemstack)
-- set new trade ItemStack
local trade_stack = inv:get_stack('trade', 1)
trade_stack:take_item(level)
inv:set_stack('trade', 1, trade_stack)
@ -582,10 +638,12 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
-- set new seed
self.player_seeds[player_name] = self:get_randomseed()
-- update node formspec
local formspec = self:get_formspec(pos, player_name)
node_meta:set_string('formspec', formspec)
core.sound_play('x_enchanting_enchant', {
-- play sound
minetest.sound_play('x_enchanting_enchant', {
gain = 0.3,
pos = pos,
max_hear_distance = 10
@ -609,7 +667,7 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
glow = 1
}
if core.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then
if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then
-- new syntax, after v5.6.0
particlespawner_def = {
amount = 50,
@ -641,7 +699,49 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
}
end
core.add_particlespawner(particlespawner_def)
minetest.add_particlespawner(particlespawner_def)
end
function XEnchanting.get_enchantments_for_group(self, item_name, meta_enchantments)
local enchantment_defs = table.copy(self.enchantment_defs)
local group_enchantments = {}
local total_cost = 0
if meta_enchantments and #meta_enchantments > 0 then
enchantment_defs = {}
for i, def in pairs(meta_enchantments) do
if self.enchantment_defs[def.id] then
enchantment_defs[def.id] = self.enchantment_defs[def.id]
end
end
end
for enchantment_id, enchantment_def in pairs(enchantment_defs) do
local is_group_compatible = false
if not enchantment_def.groups then
group_enchantments[enchantment_id] = enchantment_def
is_group_compatible = true
else
for i, group in ipairs(enchantment_def.groups) do
if minetest.get_item_group(item_name, group) > 0 then
group_enchantments[enchantment_id] = enchantment_def
is_group_compatible = true
break
end
end
end
if not is_group_compatible then
total_cost = total_cost + 1
end
end
return {
group_enchantments = group_enchantments,
writing_table_cost = total_cost
}
end
function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_def)
@ -669,7 +769,7 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d
else
---@diagnostic disable-next-line: unused-local
for i, group in ipairs(enchantment_def.groups) do
if core.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
break
end
@ -694,7 +794,7 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d
local chosen_enchantment_level = slot_lvl
-- Applying modifiers to the enchantment level
local enchantability = core.get_item_group(tool_def.name, 'enchantability')
local enchantability = minetest.get_item_group(tool_def.name, 'enchantability')
-- Generate a random number between 1 and 1+(enchantability/2), with a triangular distribution
local rand_enchantability = 1 + math.random(enchantability / 4 + 1) + math.random(enchantability / 4 + 1)
-- Choose the enchantment level
@ -879,13 +979,12 @@ local function get_list_bg(x, y)
return out
end
local function get_formspec_bg(player_name, bg_img)
local bg_image = bg_img and bg_img or 'x_enchanting_gui_formbg.png'
local info = core.get_player_information(player_name)
local bg = 'background[5,5;1,1;' .. bg_image .. ';true]'
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;' .. bg_image .. ';true;10]'
bg = 'background9[5,5;1,1;x_enchanting_gui_formbg.png;true;10]'
end
return bg
@ -893,7 +992,7 @@ end
function XEnchanting.get_formspec(self, pos, player_name, data)
local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z
local inv = core.get_meta(pos):get_inventory()
local inv = minetest.get_meta(pos):get_inventory()
---@diagnostic disable-next-line: codestyle-check
local model_scroll_open = 'model[0,0;2,3;x_enchanting_table;x_enchanting_scroll.b3d;x_enchanting_scroll_mesh.png,x_enchanting_scroll_handles_mesh.png,x_enchanting_scroll_mesh.png;89,0;false;false;' .. self.scroll_animations.scroll_open_idle[1].x .. ',' .. self.scroll_animations.scroll_open_idle[1].y .. ';0]'
---@diagnostic disable-next-line: codestyle-check
@ -934,10 +1033,10 @@ function XEnchanting.get_formspec(self, pos, player_name, data)
if inv:get_stack('trade', 1):get_count() >= i then
---@diagnostic disable-next-line: codestyle-check
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 .. core.formspec_escape(' [' .. 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
---@diagnostic disable-next-line: codestyle-check
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 .. core.formspec_escape(' [' .. 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
formspec[#formspec + 1] = 'image[2.3,' .. -0.5 + i .. ';1,1;x_enchanting_image_trade_' .. i .. '.png;]'
@ -973,76 +1072,337 @@ function XEnchanting.get_formspec(self, pos, player_name, data)
return table.concat(formspec, '')
end
function XEnchanting.get_grindstone_formspec(self, pos, player_name, data)
local _data = data or {}
local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z
local model = 'model[0,0;2,3;x_enchanting_grindstone;x_enchanting_grindstone.obj;x_enchanting_grindstone_mesh.png;0,0;true;false;]'
local formspec = {}
formspec[#formspec + 1] = 'size[8,9]'
formspec[#formspec + 1] = 'bgcolor[#080808BB;true]'
formspec[#formspec + 1] = 'listcolors[#FFFFFF00;#FFFFFF1A;#FFFFFF00;#30434C;#FFF]'
formspec[#formspec + 1] = get_formspec_bg(player_name)
formspec[#formspec + 1] = 'style_type[label;font=mono,bold]'
formspec[#formspec + 1] = 'style[slot_1,slot_2,slot_3;font=mono,bold;textcolor=#4D413A]'
formspec[#formspec + 1] = 'label[0, 0;' .. S('Disenchant') .. ']'
function XEnchanting.get_writing_table_total_data(self, props)
local inv = props.inv
-- item
formspec[#formspec + 1] = 'list[nodemeta:' .. spos .. ';item;0.5, 2.5;1, 1;]'
formspec[#formspec + 1] = 'image[0.5, 2.5;1,1;x_enchanting_gui_cloth_bg.png]'
-- result
if _data.result_disabled then
formspec[#formspec + 1] = 'image[4.75, 1.25;1.5,1.5;x_enchanting_gui_cloth_bg_corssed.png]'
else
formspec[#formspec + 1] = 'list[nodemeta:' .. spos .. ';result;5, 1.5;1, 1;]'
formspec[#formspec + 1] = 'image[5, 1.5;1,1;x_enchanting_gui_cloth_bg.png]'
local stack_item = inv:get_stack('item', 1)
local stack_item_meta = stack_item:get_meta()
local table_uses_item = stack_item_meta:get_int('x_enchanting_writing_table_uses')
print('table_uses_item', table_uses_item)
local prior_use_penalty_item = 2 ^ table_uses_item - 1
local enchantments_item = minetest.deserialize(stack_item_meta:get_string('x_enchanting')) or {}
-- sacrifice
local stack_sacrifice = inv:get_stack('sacrifice', 1)
local stack_sacrifice_meta = stack_sacrifice:get_meta()
local table_uses_sacrifice = stack_sacrifice_meta:get_int('x_enchanting_writing_table_uses')
print('table_uses_sacrifice', table_uses_sacrifice)
local prior_use_penalty_sacrifice = 2 ^ table_uses_sacrifice - 1
local enchantments_sacrifice = minetest.deserialize(stack_sacrifice_meta:get_string('x_enchanting')) or {}
local new_x_enchanting_writing_table_uses = table_uses_item
if table_uses_sacrifice > new_x_enchanting_writing_table_uses then
new_x_enchanting_writing_table_uses = table_uses_sacrifice
end
-- inventories
formspec[#formspec + 1] = 'list[current_player;main;0, 4.85;8, 1;]'
formspec[#formspec + 1] = 'list[current_player;main;0, 6.08;8, 3;8]'
formspec[#formspec + 1] = 'listring[nodemeta:' .. spos .. ';result]'
formspec[#formspec + 1] = 'listring[current_player;main]'
formspec[#formspec + 1] = 'listring[nodemeta:' .. spos .. ';item]'
formspec[#formspec + 1] = 'listring[current_player;main]'
print('enchantments_sacrifice', dump(enchantments_sacrifice))
formspec[#formspec + 1] = get_hotbar_bg(0, 4.85)
formspec[#formspec + 1] = get_list_bg(0, 6.08)
formspec[#formspec + 1] = model
local result_data = {
-- Prior Work penalties of both target and sacrifice.
total_cost = prior_use_penalty_item + prior_use_penalty_sacrifice,
show_total_cost = true,
show_crossed_arrow = false
}
return table.concat(formspec, '')
end
if stack_sacrifice:is_empty() or stack_item:is_empty() then
result_data.show_total_cost = false
function XEnchanting.has_all_cursed_ench(self, itemstack)
if itemstack:is_empty() then
return false
if not (stack_sacrifice:is_empty() and stack_item:is_empty()) then
result_data.show_crossed_arrow = true
inv:set_stack('result', 1, ItemStack(''))
end
return result_data
end
local item_stack_meta = itemstack:get_meta()
local stack_enchantment_data = core.deserialize(item_stack_meta:get_string('x_enchanting')) or {}
local stack_enchantment_data_length = get_table_length(stack_enchantment_data)
local cursed_ench = 0
-- total cost
-- If the sacrifice has enchantments, the enchantment cost.
-- get enchantment defs for item group
-- Add one level cost for every incompatible enchantment on the target
local enchantment_defs_for_group = self:get_enchantments_for_group(stack_item:get_name(), enchantments_sacrifice)
local possible_enchantments_defs = enchantment_defs_for_group.group_enchantments
-- Get cursed enchantments
for id, value in pairs(stack_enchantment_data) do
local ench_def = self.enchantment_defs[id]
result_data.total_cost = result_data.total_cost + enchantment_defs_for_group.writing_table_cost
if ench_def.cursed then
cursed_ench = cursed_ench + 1
-- remove incompatible enchantments
-- Add one level cost for every incompatible enchantment on the target
for enchanment_id, enchanment_def in pairs(table.copy(possible_enchantments_defs)) do
if enchanment_def.incompatible then
for _, enchantment in ipairs(enchantments_item) do
if table.indexof(enchanment_def.incompatible, enchantment.id) ~= -1 then
possible_enchantments_defs[enchanment_id] = nil
result_data.total_cost = result_data.total_cost + 1
end
end
end
end
return cursed_ench == stack_enchantment_data_length
-- reduce/sync current sacrifice enchantmets
local enchantments_sacrifice_copy = table.copy(enchantments_sacrifice)
enchantments_sacrifice = {}
for i, enchantment in ipairs(enchantments_sacrifice_copy) do
if possible_enchantments_defs[enchantment.id] then
table.insert(enchantments_sacrifice, enchantment)
end
end
print('enchantments_sacrifice', dump(enchantments_sacrifice))
print('enchantments_item', dump(enchantments_item))
local final_enchantments = {}
-- If the enchantment is compatible with the existing enchantments on the target:
-- add the final level of the enchantment on the resulting item multiplied by the multiplier from the table
for i, enchantment_sacrifice in ipairs(enchantments_sacrifice) do
local enchantment_upgraded = false
local multiplier = possible_enchantments_defs[enchantment_sacrifice.id].multiplier_from_item
if minetest.get_item_group(stack_sacrifice:get_name(), 'scroll') > 0 then
multiplier = possible_enchantments_defs[enchantment_sacrifice.id].multiplier_from_scroll
end
print('multiplier', multiplier)
for _, enchantment_item in ipairs(enchantments_item) do
print(enchantment_item.id .. ' == ' .. enchantment_sacrifice.id)
if enchantment_item.id == enchantment_sacrifice.id then
-- upgrade
print('--- upgrade')
print('enchantment_item', dump(enchantment_item))
print('enchantment_sacrifice', dump(enchantment_sacrifice))
if enchantment_sacrifice.level == enchantment_item.level then
local new_level = enchantment_sacrifice.level + 1
local max_level = #possible_enchantments_defs[enchantment_sacrifice.id].final_level_range
if new_level > max_level then
-- maximum level reached, still add the cost though
new_level = max_level
end
table.insert(final_enchantments, {
id = enchantment_sacrifice.id,
level = new_level,
value = possible_enchantments_defs[enchantment_sacrifice.id].level_def[new_level],
secondary = enchantment_sacrifice.secondary,
incompatible = enchantment_sacrifice.incompatible
})
-- upgrade 1 level up if not already on max level
print(enchantment_item.id, 'upgrade 1 level up')
result_data.total_cost = result_data.total_cost + multiplier * new_level
elseif enchantment_sacrifice.level > enchantment_item.level then
-- upgrade to sacrifice level
print(enchantment_item.id, 'upgrade to' .. enchantment_sacrifice.level .. ' levels up')
table.insert(final_enchantments, {
id = enchantment_sacrifice.id,
level = enchantment_sacrifice.level,
value =
possible_enchantments_defs[enchantment_sacrifice.id].level_def[enchantment_sacrifice.level],
secondary = enchantment_sacrifice.secondary,
incompatible = enchantment_sacrifice.incompatible
})
result_data.total_cost = result_data.total_cost + multiplier * enchantment_sacrifice.level
else
-- dont change enchantment on item but add cost for it
table.insert(final_enchantments, enchantment_item)
result_data.total_cost = result_data.total_cost + multiplier * enchantment_item.level
end
enchantment_upgraded = true
end
end
if not enchantment_upgraded then
-- add
print('--- add')
print('enchantment_sacrifice', dump(enchantment_sacrifice))
table.insert(final_enchantments, enchantment_sacrifice)
result_data.total_cost = result_data.total_cost + multiplier * enchantment_sacrifice.level
end
end
print('final_enchantments 1', dump(final_enchantments))
if #final_enchantments == 0 then
result_data.show_total_cost = false
result_data.show_crossed_arrow = true
inv:set_stack('result', 1, ItemStack(''))
return result_data
end
-- add remaining enchantments from the item
for i, enchantment_item in ipairs(enchantments_item) do
local has_item = false
for j, enchantment_sacrifice in ipairs(enchantments_sacrifice) do
if enchantment_item.id == enchantment_sacrifice.id then
has_item = true
end
end
if not has_item then
table.insert(final_enchantments, enchantment_item)
end
end
print('final_enchantments 2', dump(final_enchantments))
if inv:is_empty('item') and not inv:is_empty('sacrifice')
or inv:is_empty('sacrifice') and not inv:is_empty('item')
or inv:is_empty('trade')
or #final_enchantments == 0
then
result_data.show_crossed_arrow = true
inv:set_stack('result', 1, ItemStack(''))
end
if inv:is_empty('item') or inv:is_empty('sacrifice')
or #final_enchantments == 0
then
result_data.show_total_cost = false
end
result_data.enchantments = final_enchantments
print('result_data', dump(result_data))
local tool_cap_data = self:get_enchanted_tool_capabilities(
minetest.registered_tools[stack_item:get_name()] or minetest.registered_craftitems[stack_item:get_name()],
final_enchantments
)
local descriptions = self:get_enchanted_descriptions(final_enchantments)
local stack_result = ItemStack(stack_item:to_table())
local stack_result_meta = stack_result:get_meta()
print('short_description', stack_result:get_short_description())
if not stack_item:is_empty() and minetest.get_item_group(stack_item:get_name(), 'scroll') == 0 then
-- for i, enchantment in ipairs(final_enchantments) do
-- stack_meta:set_float('is_' .. enchantment.id, enchantment.value)
-- end
print('tool_cap_data', dump(tool_cap_data))
print('stack_result', dump(stack_result:to_table()))
stack_result_meta:set_tool_capabilities(tool_cap_data)
end
print('new_x_enchanting_writing_table_uses 1', new_x_enchanting_writing_table_uses)
stack_result_meta:set_int('x_enchanting_writing_table_uses', new_x_enchanting_writing_table_uses + 1)
print('new_x_enchanting_writing_table_uses 2', stack_result_meta:get_int('x_enchanting_writing_table_uses'))
stack_result_meta:set_string(
'description',
stack_result:get_short_description() .. '\n' .. descriptions.enchantments_desc
)
stack_result_meta:set_string('x_enchanting', minetest.serialize(final_enchantments))
inv:set_stack('result', 1, stack_result)
return result_data
end
--
-- Sounds
--
function XEnchanting.get_formspec_writing_table(self, pos, props)
local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z
local inv = minetest.get_meta(pos):get_inventory()
---@diagnostic disable-next-line: codestyle-check
local model_scroll_open = 'model[0,0;2,3;x_enchanting_table;x_enchanting_scroll.b3d;x_enchanting_scroll_mesh.png,x_enchanting_scroll_handles_mesh.png,x_enchanting_scroll_mesh.png;89,0;false;false;' .. self.scroll_animations.scroll_open_idle[1].x .. ',' .. self.scroll_animations.scroll_open_idle[1].y .. ';0]'
---@diagnostic disable-next-line: codestyle-check
local model_scroll_closed = 'model[0,0;2,3;x_enchanting_table;x_enchanting_scroll.b3d;x_enchanting_scroll_mesh.png,x_enchanting_scroll_handles_mesh.png,x_enchanting_scroll_mesh.png;89,0;false;false;' .. self.scroll_animations.scroll_closed_idle[1].x .. ',' .. self.scroll_animations.scroll_closed_idle[1].y .. ';0]'
local model_scroll_is_open
function XEnchanting.node_sound_wood_defaults(table)
table = table or {}
table.footstep = table.footstep or { name = 'x_enchanting_wood_footstep', gain = 0.15 }
table.dig = table.dig or { name = 'x_enchanting_wood_hit', gain = 0.5 }
table.dug = table.dug or { name = 'x_enchanting_wood_place', gain = 0.1 }
table.place = table.place or { name = 'x_enchanting_wood_place', gain = 0.15 }
return table
local player_name = props.player_name
local data = props.data or {}
local show_crossed_arrow = data.show_crossed_arrow
local show_total_cost = data.show_total_cost
local formspec = {
'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') .. ']',
-- item
'list[nodemeta:' .. spos .. ';item;2.75, 0.5;1, 1;]',
'image[2.75, 0.5;1,1;x_enchanting_gui_paper_bg.png]',
'image[3.75, 0.5;1,1;x_enchanting_gui_plus_icon.png]',
-- sacrifice
'list[nodemeta:' .. spos .. ';sacrifice;4.75, 0.5;1, 1;]',
'image[4.75, 0.5;1,1;x_enchanting_gui_paper_scroll_bg.png]',
show_crossed_arrow and 'image[5.75, 0.5;1,1;x_enchanting_gui_arrow_right_crossed_icon.png]'
or 'image[5.75, 0.5;1,1;x_enchanting_gui_arrow_right_icon.png]',
-- result
'list[nodemeta:' .. spos .. ';result;6.75, 0.5;1, 1;]',
'image[6.75, 0.5;1,1;x_enchanting_gui_paper_bg.png]',
-- trade
'list[nodemeta:' .. spos .. ';trade;6.75, 1.5;1, 1;]',
'image[6.75, 1.5;1,1;x_enchanting_gui_paper_trade_bg.png]',
-- inventories
'list[current_player;main;0, 4.85;8, 1;]',
'list[current_player;main;0, 6.08;8, 3;8]',
'listring[nodemeta:' .. spos .. ';trade]',
'listring[current_player;main]',
'listring[nodemeta:' .. spos .. ';sacrifice]',
'listring[current_player;main]',
'listring[nodemeta:' .. spos .. ';item]',
'listring[current_player;main]',
}
formspec[#formspec + 1] = get_hotbar_bg(0, 4.85)
formspec[#formspec + 1] = get_list_bg(0, 6.08)
if show_total_cost then
formspec[#formspec + 1] = 'style_type[label;font=mono,bold;textcolor=#4D413A]'
formspec[#formspec + 1] = 'label[3.125, 1.5;' .. S('Cost') .. ': ' .. data.total_cost .. ']'
end
-- -- data
-- if data then
-- for i, slot in ipairs(data.slots) do
-- if #slot.final_enchantments > 0 then
-- -- show buttons with content
-- if inv:get_stack('trade', 1):get_count() >= i then
-- ---@diagnostic disable-next-line: codestyle-check
-- 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
-- ---@diagnostic disable-next-line: codestyle-check
-- 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
-- formspec[#formspec + 1] = 'image[2.3,' .. -0.5 + i .. ';1,1;x_enchanting_image_trade_' .. i .. '.png;]'
-- else
-- -- disabled buttons
-- ---@diagnostic disable-next-line: codestyle-check
-- 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 = true
-- else
-- for i = 1, 3, 1 do
-- -- disabled buttons
-- ---@diagnostic disable-next-line: codestyle-check
-- formspec[#formspec + 1] = 'image_button[3.125,' .. -0.5 + i .. ';5.125,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';]'
-- end
-- model_scroll_is_open = false
-- end
-- if model_scroll_is_open then
-- formspec[#formspec + 1] = model_scroll_open
-- else
-- formspec[#formspec + 1] = model_scroll_closed
-- end
-- self.form_context[player_name] = {
-- data = data,
-- pos = pos
-- }
return table.concat(formspec, '')
end

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,380 +0,0 @@
---@diagnostic disable
--[[
X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2025 SaKeL
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 = core.get_translator(core.get_current_modname())
----
--- Grindstone Node
----
core.register_node('x_enchanting:grindstone', {
description = S('Grindstone'),
short_description = S('Grindstone'),
drawtype = 'mesh',
mesh = 'x_enchanting_grindstone.obj',
tiles = { 'x_enchanting_grindstone_mesh.png' },
inventory_image = 'x_enchanting_grindstone_item.png',
use_texture_alpha = 'clip',
paramtype = 'light',
paramtype2 = 'facedir',
walkable = true,
wield_scale = { x = 2, y = 2, z = 2 },
selection_box = {
type = 'fixed',
fixed = { -1 / 2, -1 / 2, -1 / 2, 1 / 2, 1 / 2 - 1 / 16, 1 / 2 }
},
collision_box = {
type = 'fixed',
fixed = { -1 / 2, -1 / 2, -1 / 2, 1 / 2, 1 / 2 - 1 / 16, 1 / 2 }
},
sounds = XEnchanting.node_sound_wood_defaults(),
is_ground_content = false,
groups = { choppy = 2, oddly_breakable_by_hand = 2 },
stack_max = 1,
mod_origin = 'x_enchanting',
---@param pos Vector
on_construct = function(pos)
local meta = core.get_meta(pos)
local inv = meta:get_inventory()
meta:set_string('infotext', S('Grindstone'))
meta:set_string('owner', '')
inv:set_size('item', 1)
inv:set_size('result', 1)
end,
---@param pos Vector
---@param placer ObjectRef | nil
---@param itemstack ItemStack
---@param pointed_thing PointedThingDef
---@diagnostic disable-next-line: unused-local
after_place_node = function(pos, placer, itemstack, pointed_thing)
local meta = core.get_meta(pos)
if not placer then
return
end
local player_name = placer:get_player_name()
meta:set_string('owner', player_name)
meta:set_string('infotext', S('Grindstone') .. ' (' .. S('owned by') .. ' ' .. player_name .. ')')
local formspec = XEnchanting:get_grindstone_formspec(pos, player_name)
meta:set_string('formspec', formspec)
end,
---@param pos Vector
---@param node NodeDef
---@param clicker ObjectRef
---@param itemstack ItemStack
---@param pointed_thing? PointedThingDef
---@diagnostic disable-next-line: unused-local
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = core.get_meta(pos)
local p_name = clicker:get_player_name()
local inv = meta:get_inventory()
local item_stack = inv:get_stack('item', 1)
local has_all_cursed_ench = XEnchanting:has_all_cursed_ench(item_stack)
if core.is_protected(pos, p_name) then
return itemstack
end
core.sound_play('x_enchanting_wood_hit', {
gain = 0.5,
pos = pos,
max_hear_distance = 10
}, true)
local formspec = XEnchanting:get_grindstone_formspec(pos, p_name, { result_disabled = has_all_cursed_ench })
meta:set_string('formspec', formspec)
return itemstack
end,
---@param pos Vector
---@param intensity? number
---@return table | nil
---@diagnostic disable-next-line: unused-local
on_blast = function(pos, intensity)
if core.is_protected(pos, '') then
return
end
local drops = {}
local inv = core.get_meta(pos):get_inventory()
local stack_item = inv:get_stack('item', 1)
if not stack_item:is_empty() then
drops[#drops + 1] = stack_item:to_table()
end
drops[#drops + 1] = 'x_enchanting:grindstone'
core.remove_node(pos)
return drops
end,
---@param pos Vector
---@param player? ObjectRef
can_dig = function(pos, player)
if not player then
return false
end
local inv = core.get_meta(pos):get_inventory()
return inv:is_empty('item')
and inv:is_empty('result')
and not core.is_protected(pos, player:get_player_name())
end,
---@diagnostic disable-next-line: unused-local
on_rotate = function(pos, node, user, mode, new_param2)
return false
end,
---@param pos Vector
---@param listname string
---@param index number
---@param stack ItemStack
---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local st_meta = stack:get_meta()
local is_enchanted = st_meta:get_int('is_enchanted')
if listname == 'item' and is_enchanted == 1 then
return stack:get_count()
end
return 0
end,
---@param pos Vector
---@param listname string
---@param index number
---@param stack ItemStack
---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
return stack:get_count()
end,
---@param pos Vector
---@param from_list string
---@param from_index number
---@param to_list string
---@param to_index number
---@param count number
---@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)
return 0
end,
---@param pos Vector
---@param listname string
---@param index number
---@param stack ItemStack
---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
on_metadata_inventory_put = function(pos, listname, index, stack, player)
--
-- Create new itemstack with removed enchantments (excl. curses) and populate the result slot with this new item
--
local meta = core.get_meta(pos)
local p_name = player:get_player_name()
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')
local stack_enchantment_data = core.deserialize(item_stack_meta:get_string('x_enchanting')) or {}
local has_all_cursed_ench = XEnchanting:has_all_cursed_ench(item_stack)
if not inv:is_empty('item') and is_enchanted == 1 and not has_all_cursed_ench then
-- Discenchanted item
local has_curse = false
local current_enchantments = {}
for id, value in pairs(stack_enchantment_data) do
-- Remove enchantment meta data (excl. cursed)
local ench_def = XEnchanting.enchantment_defs[id]
if not ench_def.cursed then
item_stack_meta:set_float('is_' .. id, 0)
stack_enchantment_data[id] = nil
else
has_curse = true
end
-- Get descriptions
if stack_enchantment_data[id] then
local level
-- Find level
for i, v in ipairs(ench_def.level_def) do
if v == value.value then
level = i
break
end
end
table.insert(current_enchantments, {
id = id,
value = value.value,
level = level,
secondary = ench_def.secondary,
incompatible = ench_def.incompatible
})
end
end
if not has_curse then
-- Reset meta data if not cursed
item_stack_meta:set_string('inventory_image', '')
item_stack_meta:set_string('inventory_overlay', '')
item_stack_meta:set_string('wield_image', '')
item_stack_meta:set_string('wield_overlay', '')
item_stack_meta:set_string('description', '')
item_stack_meta:set_string('short_description', '')
item_stack_meta:set_int('is_enchanted', 0)
end
local descriptions = XEnchanting:get_enchanted_descriptions(current_enchantments)
-- Upgrade description with remaining enchantments
if #current_enchantments > 0 then
local item_stack_def = core.registered_tools[item_stack:get_name()]
item_stack_meta:set_string('description', (item_stack_def and item_stack_def.description or '') .. '\n' .. descriptions.enchantments_desc)
end
item_stack_meta:set_tool_capabilities(nil)
item_stack_meta:set_string('x_enchanting', core.serialize(stack_enchantment_data))
inv:set_stack('result', 1, item_stack)
end
local formspec = XEnchanting:get_grindstone_formspec(pos, p_name, { result_disabled = has_all_cursed_ench })
meta:set_string('formspec', formspec)
end,
---@param pos Vector
---@param listname string
---@param index number
---@param stack ItemStack
---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
on_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = core.get_meta(pos)
local p_name = player:get_player_name()
local inv = meta:get_inventory()
local result_stack = inv:get_stack('result', 1)
local item_stack = inv:get_stack('item', 1)
local item_stack_meta = item_stack:get_meta()
local has_all_cursed_ench = XEnchanting:has_all_cursed_ench(item_stack)
local stack_enchantment_data = core.deserialize(item_stack_meta:get_string('x_enchanting')) or {}
local result_payment_stack = ItemStack({ name = 'default:mese_crystal_fragment' })
if item_stack:is_empty() or has_all_cursed_ench then
-- Remove result item
inv:remove_item('result', result_stack)
end
-- Collect total result
local result_total = 0
if result_total == 0 then
-- get payback result (excl. cursed enchantments) from the original item
for id, value in pairs(stack_enchantment_data) do
local ench_def = XEnchanting.enchantment_defs[id]
local lvl_index
if not ench_def.cursed then
-- find level index
for i, v in ipairs(ench_def.level_def) do
if v == stack_enchantment_data[id].value then
lvl_index = i
end
end
end
if lvl_index then
local final_level_range = ench_def.final_level_range[lvl_index]
local range_max = final_level_range[1] + final_level_range[2]
local range_min = math.floor(range_max / 2)
local result = math.random(range_min, range_max)
result_total = result_total + result
end
end
if result_total > result_payment_stack:get_stack_max() then
result_total = result_payment_stack:get_stack_max()
elseif result_total == 0 then
result_total = 1
end
end
result_total = math.floor(result_total / 10)
result_payment_stack:set_count(result_total)
if listname == 'result' and result_stack:is_empty() then
-- Drop payment result
inv:set_stack('item', 1, ItemStack(''))
core.item_drop(result_payment_stack, player, player:get_pos())
core.sound_play('x_enchanting_disenchant', {
gain = 0.3,
pos = pos,
max_hear_distance = 10
}, true)
-- particles
local particlespawner_def = {
amount = 50,
time = 0.5,
minpos = { x = pos.x - 0.5, y = pos.y + 0.5, z = pos.z - 0.5 },
maxpos = { x = pos.x + 0.5, y = pos.y + 0.5, z = pos.z + 0.5 },
minvel = { x = -1.5, y = -0.5, z = -1.5 },
maxvel = { x = 1.5, y = -1.5, z = 1.5 },
minacc = { x = -3.5, y = -6.5, z = -3.5 },
maxacc = { x = 5.5, y = -7.5, z = 5.5 },
minexptime = 0.5,
maxexptime = 1,
minsize = 0.5,
maxsize = 1,
texture = 'x_enchanting_scroll_particle.png^[colorize:#FFE5C2:256',
glow = 1
}
core.add_particlespawner(particlespawner_def)
end
local formspec = XEnchanting:get_grindstone_formspec(pos, p_name)
meta:set_string('formspec', formspec)
end
})
----
-- Recipe
---
core.register_craft({
output = 'x_enchanting:grindstone',
recipe = {
{ 'group:stick', 'stairs:slab_stone', 'group:stick' },
{ 'group:wood', '', 'group:wood' }
}
})

View File

@ -1,6 +1,6 @@
--[[
X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2025 SaKeL
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
@ -16,12 +16,12 @@
License along with this library; if not, write to juraj.vajda@gmail.com
--]]
local path = core.get_modpath('x_enchanting')
local mod_start_time = core.get_us_time()
local path = minetest.get_modpath('x_enchanting')
local mod_start_time = minetest.get_us_time()
dofile(path .. '/api.lua')
dofile(path .. '/table.lua')
dofile(path .. '/grindstone.lua')
dofile(path .. '/writing_table.lua')
---Check if string X starts with string Y
---@param str string
@ -31,23 +31,30 @@ local function starts_with(str, start)
return str:sub(1, #start) == start
end
core.register_on_mods_loaded(function()
minetest.register_on_mods_loaded(function()
-- Tools override
for name, tool_def in pairs(core.registered_tools) do
for name, tool_def in pairs(minetest.registered_tools) do
if XEnchanting:has_tool_group(name) then
XEnchanting:set_tool_enchantability(tool_def)
XEnchanting:set_enchantability(tool_def)
end
end
-- Craft items override
for name, tool_def in pairs(minetest.registered_craftitems) do
if XEnchanting:has_tool_group(name) then
XEnchanting:set_enchantability(tool_def)
end
end
-- Ores override - Fortune
for _, def in pairs(core.registered_ores) do
for _, def in pairs(minetest.registered_ores) do
if not XEnchanting.registered_ores[def.ore] then
XEnchanting.registered_ores[def.ore] = true
end
end
-- Entities override - Looting
for name, def in pairs(core.registered_entities) do
for name, def in pairs(minetest.registered_entities) do
if starts_with(name, 'mobs_animal:')
or starts_with(name, 'mobs_monster:')
then
@ -103,7 +110,7 @@ core.register_on_mods_loaded(function()
stack:set_count(stack:get_count() * chance)
if stack:get_count() > 0 then
core.item_drop(stack, puncher, pos)
minetest.item_drop(stack, puncher, pos)
end
end
end
@ -161,7 +168,7 @@ core.register_on_mods_loaded(function()
stack:set_count(stack:get_count() * chance)
if stack:get_count() > 0 then
core.item_drop(stack, puncher, pos)
minetest.item_drop(stack, puncher, pos)
end
end
end
@ -173,7 +180,7 @@ core.register_on_mods_loaded(function()
end)
---@diagnostic disable-next-line: unused-local
core.register_on_joinplayer(function(player, last_login)
minetest.register_on_joinplayer(function(player, last_login)
XEnchanting.form_context[player:get_player_name()] = nil
if not XEnchanting.player_seeds[player:get_player_name()] then
@ -182,20 +189,20 @@ core.register_on_joinplayer(function(player, last_login)
end)
---@diagnostic disable-next-line: unused-local
core.register_on_leaveplayer(function(player, timed_out)
minetest.register_on_leaveplayer(function(player, timed_out)
XEnchanting.form_context[player:get_player_name()] = nil
end)
local old_handle_node_drops = core.handle_node_drops
local old_handle_node_drops = minetest.handle_node_drops
function core.handle_node_drops(pos, drops, digger)
function minetest.handle_node_drops(pos, drops, digger)
if not digger
or not digger:is_player()
then
return old_handle_node_drops(pos, drops, digger)
end
local node = core.get_node(pos)
local node = minetest.get_node(pos)
local wield_stack = digger:get_wielded_item()
local wield_stack_meta = wield_stack:get_meta()
@ -207,13 +214,13 @@ function core.handle_node_drops(pos, drops, digger)
for _, itemstring in ipairs(drops) do
if XEnchanting.registered_ores[node.name]
or core.get_item_group(node.name, 'stone') > 0
or core.get_item_group(node.name, 'soil') > 0
or core.get_item_group(node.name, 'sand') > 0
or core.get_item_group(node.name, 'snowy') > 0
or core.get_item_group(node.name, 'slippery') > 0
or core.get_item_group(node.name, 'tree') > 0
or core.get_item_group(node.name, 'leaves') > 0
or minetest.get_item_group(node.name, 'stone') > 0
or minetest.get_item_group(node.name, 'soil') > 0
or minetest.get_item_group(node.name, 'sand') > 0
or minetest.get_item_group(node.name, 'snowy') > 0
or minetest.get_item_group(node.name, 'slippery') > 0
or minetest.get_item_group(node.name, 'tree') > 0
or minetest.get_item_group(node.name, 'leaves') > 0
then
local tool_capabilities = wield_stack:get_tool_capabilities()
local stack = ItemStack(itemstring)
@ -238,7 +245,7 @@ function core.handle_node_drops(pos, drops, digger)
local silk_touch = wield_stack_meta:get_float('is_silk_touch')
if silk_touch > 0
and core.get_item_group(node.name, 'no_silktouch') == 0
and minetest.get_item_group(node.name, 'no_silktouch') == 0
then
-- drop raw item/node
return old_handle_node_drops(pos, { ItemStack(node.name) }, digger)
@ -248,7 +255,7 @@ function core.handle_node_drops(pos, drops, digger)
end
---@diagnostic disable-next-line: unused-local
core.register_on_player_hpchange(function(player, hp_change, reason)
minetest.register_on_player_hpchange(function(player, hp_change, reason)
-- Curse of Vanishing
if (player:get_hp() + hp_change) <= 0 then
-- Going to die
@ -273,9 +280,9 @@ core.register_on_player_hpchange(function(player, hp_change, reason)
end, true)
-- Knockback (only for players)
local old_calculate_knockback = core.calculate_knockback
local old_calculate_knockback = minetest.calculate_knockback
function core.calculate_knockback(player, hitter, time_from_last_punch,
function minetest.calculate_knockback(player, hitter, time_from_last_punch,
tool_capabilities, dir, distance, damage)
if hitter and hitter:is_player() then
local hitter_wield_stack = hitter:get_wielded_item()
@ -307,6 +314,6 @@ function core.calculate_knockback(player, hitter, time_from_last_punch,
tool_capabilities, dir, distance, damage)
end
local mod_end_time = (core.get_us_time() - mod_start_time) / 1000000
local mod_end_time = (minetest.get_us_time() - mod_start_time) / 1000000
print('[Mod] x_enchanting loaded.. [' .. mod_end_time .. 's]')

View File

@ -1,6 +1,6 @@
name = x_enchanting
description = Adds Enchanting Mechanics and API.
depends =
optional_depends = xdecor, item_drop, stairs, enchanting
optional_depends = xdecor, item_drop
supported_games = minetest_game
min_minetest_version = 5.4

View File

@ -1,928 +0,0 @@
# Blender v2.83.20 OBJ File: 'x_enchanting_grindstone.blend'
# www.blender.org
mtllib x_enchanting_grindstone.mtl
o x_enchanting_grindstone.vox
v 0.125000 -0.499000 0.437500
v 0.187500 -0.499000 0.312500
v 0.125000 -0.499000 -0.375000
v 0.125000 -0.499000 -0.437500
v 0.125000 -0.311500 0.375000
v -0.250000 -0.311500 0.312500
v 0.187500 -0.311500 0.312500
v 0.187500 -0.311500 -0.312500
v 0.125000 -0.311500 -0.437500
v -0.250000 -0.311500 -0.312500
v 0.187500 -0.249000 0.375000
v 0.187500 -0.186500 0.375000
v -0.250000 -0.186500 0.312500
v -0.250000 -0.186500 -0.312500
v -0.250000 -0.124000 0.312500
v 0.187500 -0.186500 -0.312500
v -0.312500 -0.124000 0.500000
v 0.187500 -0.124000 0.187500
v -0.312500 -0.061500 0.062500
v 0.187500 -0.061500 0.062500
v -0.125000 -0.061500 -0.062500
v 0.187500 -0.124000 -0.312500
v -0.312500 -0.124000 -0.500000
v -0.312500 0.001000 0.500000
v -0.312500 -0.061500 -0.062500
v 0.187500 0.001000 -0.062500
v -0.312500 0.001000 -0.500000
v -0.375000 0.063500 -0.062500
v -0.125000 -0.311500 0.062500
v 0.312500 0.376000 -0.062500
v -0.187500 -0.499000 0.312500
v -0.187500 -0.499000 -0.312500
v -0.187500 -0.499000 -0.375000
v -0.125000 -0.499000 -0.375000
v -0.187500 -0.311500 -0.312500
v -0.187500 -0.311500 0.312500
v -0.187500 -0.311500 0.062500
v 0.250000 -0.311500 -0.312500
v -0.187500 -0.186500 0.312500
v -0.187500 -0.186500 0.375000
v -0.187500 -0.186500 0.062500
v -0.187500 -0.186500 -0.375000
v -0.187500 -0.186500 -0.312500
v 0.250000 -0.186500 -0.312500
v -0.187500 -0.124000 0.312500
v -0.187500 -0.124000 0.125000
v 0.125000 -0.061500 0.062500
v 0.125000 -0.311500 0.062500
v -0.187500 -0.061500 -0.062500
v 0.312500 -0.124000 -0.500000
v 0.312500 0.001000 0.500000
v -0.187500 -0.061500 0.062500
v -0.187500 0.001000 0.125000
v 0.125000 -0.061500 -0.062500
v 0.125000 0.063500 0.062500
v 0.437500 0.251000 0.062500
v 0.437500 0.251000 -0.062500
v 0.500000 0.376000 -0.062500
v 0.250000 -0.499000 0.437500
v 0.187500 -0.499000 -0.312500
v 0.250000 -0.499000 -0.312500
v 0.187500 -0.499000 -0.375000
v -0.125000 -0.311500 0.437500
v -0.125000 -0.311500 -0.375000
v 0.125000 -0.186500 0.437500
v -0.125000 -0.186500 -0.375000
v 0.062500 -0.186500 -0.375000
v 0.125000 -0.186500 -0.375000
v 0.250000 -0.124000 0.437500
v -0.187500 -0.124000 -0.312500
v -0.250000 -0.124000 -0.312500
v -0.125000 -0.124000 -0.375000
v -0.187500 -0.124000 0.500000
v 0.312500 -0.124000 0.500000
v 0.187500 0.001000 0.062500
v 0.312500 -0.061500 0.062500
v -0.375000 0.063500 0.062500
v -0.187500 0.001000 0.062500
v 0.500000 0.251000 0.062500
v 0.500000 0.376000 0.062500
v -0.125000 -0.499000 0.375000
v 0.125000 -0.499000 0.375000
v -0.250000 -0.499000 0.312500
v -0.250000 -0.499000 -0.437500
v -0.125000 -0.499000 -0.437500
v -0.125000 -0.311500 0.375000
v -0.125000 -0.311500 -0.312500
v 0.125000 -0.186500 0.375000
v 0.125000 -0.249000 0.375000
v 0.125000 -0.186500 -0.437500
v -0.125000 -0.186500 0.375000
v 0.187500 -0.186500 0.312500
v 0.250000 -0.124000 0.312500
v 0.125000 -0.124000 -0.437500
v -0.125000 -0.124000 0.375000
v -0.187500 0.001000 0.375000
v 0.312500 -0.061500 -0.062500
v 0.437500 -0.061500 -0.062500
v -0.312500 0.001000 -0.062500
v -0.187500 0.001000 -0.062500
v -0.125000 0.063500 -0.062500
v 0.312500 0.063500 -0.062500
v 0.312500 0.001000 -0.062500
v 0.500000 0.251000 -0.062500
v -0.125000 0.313500 -0.312500
v -0.250000 -0.499000 0.437500
v -0.187500 -0.499000 0.375000
v -0.125000 -0.499000 0.437500
v 0.187500 -0.499000 0.375000
v 0.250000 -0.499000 0.312500
v -0.250000 -0.499000 -0.312500
v 0.250000 -0.499000 -0.437500
v 0.125000 -0.311500 0.437500
v -0.125000 -0.311500 0.312500
v 0.250000 -0.311500 0.312500
v -0.125000 -0.311500 -0.437500
v 0.062500 -0.311500 -0.375000
v 0.125000 -0.311500 -0.375000
v -0.250000 -0.124000 0.437500
v -0.187500 -0.124000 0.437500
v -0.125000 -0.124000 0.500000
v 0.125000 -0.124000 0.437500
v -0.125000 -0.124000 0.437500
v 0.125000 -0.124000 0.375000
v 0.187500 -0.124000 0.312500
v 0.250000 -0.124000 -0.312500
v 0.125000 -0.124000 -0.375000
v -0.250000 -0.124000 -0.437500
v -0.125000 -0.124000 -0.437500
v 0.250000 -0.124000 -0.437500
v -0.375000 -0.061500 0.062500
v -0.125000 -0.061500 0.062500
v 0.437500 -0.061500 0.062500
v -0.375000 -0.061500 -0.062500
v 0.187500 -0.061500 -0.062500
v -0.125000 -0.186500 0.437500
v 0.250000 -0.186500 0.312500
v -0.125000 -0.186500 -0.437500
v 0.187500 0.001000 0.375000
v 0.187500 0.001000 0.187500
v -0.312500 0.001000 0.062500
v 0.312500 0.001000 0.062500
v -0.187500 0.001000 -0.375000
v 0.187500 0.001000 -0.375000
v 0.312500 0.001000 -0.500000
v 0.312500 0.063500 0.062500
v -0.125000 0.313500 0.312500
v -0.125000 0.313500 -0.062500
v 0.312500 0.376000 0.062500
v -0.125000 0.063500 0.062500
v 0.125000 -0.311500 -0.312500
v 0.125000 0.063500 -0.062500
v 0.125000 0.313500 -0.312500
v 0.125000 -0.311500 0.312500
v 0.125000 0.313500 0.312500
v 0.125000 0.313500 -0.062500
vt 0.781250 0.968750
vt 0.843750 0.812500
vt 0.843750 0.968750
vt 0.625000 0.437500
vt 0.625000 0.375000
vt 0.593750 0.421875
vt 0.968750 0.453125
vt 1.000000 0.500000
vt 0.968750 0.421875
vt 0.437500 0.687500
vt 0.562500 0.843750
vt 0.437500 0.843750
vt 0.718750 0.062500
vt 0.687500 0.109375
vt 0.718750 0.109375
vt 0.562500 0.093750
vt 0.687500 0.078125
vt 0.687500 0.093750
vt 0.437500 0.343750
vt 0.437500 0.500000
vt 0.375000 0.468750
vt 0.625000 0.093750
vt 0.593750 0.109375
vt 0.625000 0.109375
vt 0.625000 0.171875
vt 0.593750 0.187500
vt 0.625000 0.187500
vt 0.718750 0.500000
vt 0.718750 0.468750
vt 0.656250 0.468750
vt 0.593750 0.218750
vt 0.625000 0.375000
vt 0.593750 0.375000
vt 0.468750 0.671875
vt 0.406250 0.671875
vt 0.187500 0.656250
vt 0.625000 0.500000
vt 0.468750 0.468750
vt 0.593750 0.468750
vt 0.750000 0.796875
vt 0.687500 0.859375
vt 0.687500 0.796875
vt 0.718750 0.859375
vt 0.718750 0.937500
vt 0.656250 0.890625
vt 0.718750 0.140625
vt 0.687500 0.187500
vt 0.718750 0.187500
vt 0.093750 0.593750
vt 0.312500 0.593750
vt 0.312500 0.625000
vt 0.968750 0.421875
vt 1.000000 0.453125
vt 0.968750 0.453125
vt 0.562500 0.093750
vt 0.593750 0.140625
vt 0.562500 0.140625
vt 0.625000 0.453125
vt 0.656250 0.468750
vt 0.625000 0.500000
vt 0.687500 0.750000
vt 0.750000 0.734375
vt 0.750000 0.750000
vt 0.625000 0.109375
vt 0.656250 0.093750
vt 0.656250 0.109375
vt 0.625000 0.187500
vt 0.656250 0.171875
vt 0.656250 0.187500
vt 0.125000 0.843750
vt 0.125000 0.906250
vt 0.187500 0.906250
vt 0.468750 0.640625
vt 0.406250 0.640625
vt 0.187500 0.625000
vt 0.625000 0.734375
vt 0.687500 0.812500
vt 0.625000 0.812500
vt 0.437500 0.500000
vt 0.625000 0.500000
vt 0.593750 0.468750
vt 0.062500 0.468750
vt 0.000000 0.500000
vt 0.000000 0.343750
vt 0.750000 0.562500
vt 0.937500 0.562500
vt 0.843750 0.593750
vt 0.125000 0.937500
vt 0.000000 0.843750
vt 0.000000 1.000000
vt 0.500000 0.343750
vt 0.531250 0.390625
vt 0.500000 0.390625
vt 0.687500 0.218750
vt 0.718750 0.265625
vt 0.687500 0.265625
vt 0.531250 0.109375
vt 0.562500 0.093750
vt 0.562500 0.109375
vt 0.625000 0.296875
vt 0.656250 0.281250
vt 0.656250 0.296875
vt 0.562500 0.734375
vt 0.625000 0.812500
vt 0.562500 0.812500
vt 0.218750 0.546875
vt 0.281250 0.593750
vt 0.218750 0.578125
vt 0.156250 0.671875
vt 0.187500 0.687500
vt 0.062500 0.687500
vt 0.750000 0.765625
vt 0.687500 0.765625
vt 0.437500 0.375000
vt 0.468750 0.375000
vt 0.468750 0.421875
vt 0.718750 0.265625
vt 0.687500 0.312500
vt 0.718750 0.312500
vt 0.562500 0.281250
vt 0.531250 0.265625
vt 0.562500 0.265625
vt 0.656250 0.296875
vt 0.625000 0.312500
vt 0.656250 0.312500
vt 0.687500 0.828125
vt 0.625000 0.859375
vt 0.625000 0.828125
vt 0.531250 0.546875
vt 0.593750 0.593750
vt 0.531250 0.578125
vt 0.187500 0.781250
vt 0.312500 0.687500
vt 0.312500 0.843750
vt 0.562500 0.171875
vt 0.593750 0.218750
vt 0.562500 0.218750
vt 0.656250 0.984375
vt 0.718750 0.984375
vt 0.656250 0.968750
vt 0.312500 0.625000
vt 0.625000 0.593750
vt 0.625000 0.625000
vt 0.000000 0.640625
vt 0.125000 0.640625
vt 0.031250 0.656250
vt 0.312500 0.843750
vt 0.437500 0.687500
vt 0.312500 0.687500
vt 0.656250 0.234375
vt 0.625000 0.218750
vt 0.625000 0.250000
vt 0.468750 0.421875
vt 0.468750 0.406250
vt 0.500000 0.406250
vt 0.562500 0.062500
vt 0.687500 0.078125
vt 0.687500 0.062500
vt 0.687500 0.281250
vt 0.687500 0.265625
vt 0.656250 0.265625
vt 0.531250 0.328125
vt 0.500000 0.328125
vt 0.500000 0.234375
vt 0.687500 0.140625
vt 0.593750 0.156250
vt 0.562500 0.140625
vt 0.593750 0.218750
vt 0.562500 0.375000
vt 0.593750 0.375000
vt 0.562500 0.156250
vt 0.562500 0.171875
vt 0.593750 0.171875
vt 0.468750 0.312500
vt 0.500000 0.296875
vt 0.500000 0.312500
vt 0.531250 0.203125
vt 0.500000 0.109375
vt 0.468750 0.093750
vt 0.531250 0.093750
vt 0.000000 0.187500
vt 0.031250 0.234375
vt 0.031250 0.296875
vt 0.750000 0.750000
vt 0.687500 0.734375
vt 0.625000 0.703125
vt 0.687500 0.703125
vt 0.625000 0.703125
vt 0.687500 0.687500
vt 0.687500 0.703125
vt 0.625000 0.812500
vt 0.687500 0.828125
vt 0.625000 0.828125
vt 0.625000 0.687500
vt 0.562500 0.734375
vt 0.562500 0.687500
vt 0.562500 0.859375
vt 0.625000 0.812500
vt 0.625000 0.859375
vt 0.531250 0.171875
vt 0.500000 0.125000
vt 0.531250 0.125000
vt 0.187500 0.687500
vt 0.187500 0.750000
vt 0.125000 0.750000
vt 0.437500 0.937500
vt 0.437500 1.000000
vt 0.312500 1.000000
vt 0.562500 0.906250
vt 0.437500 0.843750
vt 0.437500 0.906250
vt 0.750000 0.781250
vt 0.937500 0.781250
vt 0.937500 0.812500
vt 0.781250 0.812500
vt 0.750000 0.812500
vt 0.750000 1.000000
vt 0.750000 0.968750
vt 0.937500 1.000000
vt 0.937500 0.968750
vt 0.468750 0.375000
vt 0.437500 0.375000
vt 0.468750 0.421875
vt 0.437500 0.453125
vt 0.468750 0.453125
vt 0.593750 0.453125
vt 0.593750 0.437500
vt 0.593750 0.375000
vt 1.000000 0.375000
vt 0.968750 0.375000
vt 0.656250 0.421875
vt 0.656250 0.375000
vt 0.843750 0.484375
vt 0.843750 0.500000
vt 0.968750 0.468750
vt 0.781250 0.500000
vt 0.781250 0.484375
vt 0.625000 0.453125
vt 0.656250 0.453125
vt 0.562500 0.687500
vt 0.687500 0.062500
vt 0.562500 0.078125
vt 0.375000 0.375000
vt 0.250000 0.375000
vt 0.218750 0.343750
vt 0.218750 0.375000
vt 0.218750 0.500000
vt 0.281250 0.468750
vt 0.218750 0.468750
vt 0.593750 0.093750
vt 0.593750 0.171875
vt 0.625000 0.218750
vt 0.406250 0.687500
vt 0.187500 0.687500
vt 0.687500 0.656250
vt 0.687500 0.687500
vt 0.468750 0.687500
vt 0.593750 0.375000
vt 0.625000 0.375000
vt 0.593750 0.421875
vt 0.437500 0.500000
vt 0.437500 0.453125
vt 0.468750 0.453125
vt 0.562500 0.453125
vt 0.562500 0.421875
vt 0.593750 0.453125
vt 0.750000 0.859375
vt 0.750000 0.968750
vt 0.656250 0.968750
vt 0.562500 0.890625
vt 0.562500 0.859375
vt 0.593750 0.875000
vt 0.593750 0.859375
vt 0.656250 0.875000
vt 0.656250 0.859375
vt 0.750000 0.937500
vt 0.687500 0.140625
vt 0.000000 0.625000
vt 0.000000 0.593750
vt 0.062500 0.593750
vt 0.968750 0.375000
vt 1.000000 0.375000
vt 1.000000 0.500000
vt 0.843750 0.500000
vt 0.968750 0.468750
vt 0.843750 0.484375
vt 0.781250 0.484375
vt 0.781250 0.500000
vt 0.750000 0.500000
vt 0.750000 0.468750
vt 0.781250 0.453125
vt 0.781250 0.421875
vt 0.593750 0.093750
vt 0.625000 0.375000
vt 0.656250 0.375000
vt 0.656250 0.421875
vt 0.656250 0.453125
vt 0.687500 0.734375
vt 0.625000 0.093750
vt 0.625000 0.171875
vt 0.187500 0.937500
vt 0.312500 0.843750
vt 0.187500 1.000000
vt 0.312500 1.000000
vt 0.406250 0.656250
vt 0.187500 0.656250
vt 0.687500 0.625000
vt 0.687500 0.656250
vt 0.468750 0.656250
vt 0.687500 0.734375
vt 0.468750 0.468750
vt 0.218750 0.343750
vt 0.062500 0.375000
vt 0.218750 0.375000
vt 0.218750 0.468750
vt 0.218750 0.500000
vt 0.843750 0.750000
vt 0.937500 0.750000
vt 0.937500 0.781250
vt 0.750000 0.781250
vt 0.750000 0.750000
vt 0.781250 0.750000
vt 0.781250 0.593750
vt 0.750000 0.593750
vt 0.937500 0.593750
vt 0.531250 0.343750
vt 0.718750 0.218750
vt 0.531250 0.093750
vt 0.625000 0.281250
vt 0.625000 0.734375
vt 0.031250 0.593750
vt 0.031250 0.500000
vt 0.093750 0.546875
vt 0.093750 0.500000
vt 0.093750 0.578125
vt 0.093750 0.593750
vt 0.062500 0.593750
vt 0.218750 0.500000
vt 0.281250 0.500000
vt 0.218750 0.593750
vt 0.156250 0.656250
vt 0.187500 0.656250
vt 0.062500 0.656250
vt 0.093750 0.671875
vt 0.093750 0.656250
vt 0.687500 0.265625
vt 0.531250 0.281250
vt 0.625000 0.296875
vt 0.687500 0.859375
vt 0.406250 0.578125
vt 0.406250 0.593750
vt 0.343750 0.593750
vt 0.343750 0.500000
vt 0.406250 0.546875
vt 0.406250 0.500000
vt 0.531250 0.500000
vt 0.593750 0.500000
vt 0.531250 0.593750
vt 0.125000 0.843750
vt 0.125000 0.781250
vt 0.593750 0.171875
vt 0.593750 0.921875
vt 0.593750 1.000000
vt 0.656250 1.000000
vt 0.562500 0.890625
vt 0.562500 0.921875
vt 0.656250 0.890625
vt 0.718750 1.000000
vt 0.750000 1.000000
vt 0.750000 0.968750
vt 0.312500 0.593750
vt 0.031250 0.671875
vt 0.000000 0.671875
vt 0.125000 0.671875
vt 0.093750 0.656250
vt 0.093750 0.671875
vt 0.437500 0.843750
vt 0.656250 0.218750
vt 0.687500 0.250000
vt 0.687500 0.234375
vt 0.531250 0.421875
vt 0.562500 0.078125
vt 0.656250 0.250000
vt 0.625000 0.250000
vt 0.625000 0.281250
vt 0.500000 0.171875
vt 0.687500 0.156250
vt 0.562500 0.156250
vt 0.562500 0.218750
vt 0.687500 0.171875
vt 0.687500 0.156250
vt 0.468750 0.296875
vt 0.468750 0.109375
vt 0.500000 0.187500
vt 0.468750 0.234375
vt 0.437500 0.296875
vt 0.437500 0.234375
vt 0.468750 0.328125
vt 0.500000 0.343750
vt 0.468750 0.203125
vt 0.406250 0.328125
vt 0.000000 0.343750
vt 0.312500 0.312500
vt 0.406250 0.312500
vt 0.406250 0.203125
vt 0.406250 0.218750
vt 0.343750 0.218750
vt 0.093750 0.328125
vt 0.093750 0.312500
vt 0.093750 0.203125
vt 0.093750 0.218750
vt 0.031250 0.328125
vt 0.062500 0.234375
vt 0.062500 0.296875
vt 0.031250 0.203125
vt 0.687500 0.750000
vt 0.625000 0.734375
vt 0.625000 0.687500
vt 0.687500 0.812500
vt 0.625000 0.734375
vt 0.562500 0.812500
vt 0.000000 0.687500
vt 0.000000 0.843750
vt 0.312500 0.937500
vt 0.437500 0.843750
vt 0.437500 1.000000
vt 0.562500 1.000000
vt 0.562500 0.843750
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
usemtl grindstone
s off
f 13/1/1 10/2/1 6/3/1
f 11/4/2 109/5/2 5/6/2
f 16/7/1 144/8/1 8/9/1
f 114/10/3 155/11/3 147/12/3
f 113/13/1 82/14/1 1/15/1
f 65/16/4 91/17/4 136/18/4
f 24/19/4 51/20/4 139/21/4
f 122/22/1 88/23/1 65/24/1
f 127/25/1 90/26/1 68/27/1
f 140/28/1 18/29/1 125/30/1
f 44/31/4 92/32/4 137/33/4
f 19/34/1 25/35/1 23/36/1
f 144/37/3 72/38/3 127/39/3
f 77/40/4 101/41/4 28/42/4
f 133/43/3 56/44/3 146/45/3
f 118/46/1 4/47/1 3/48/1
f 121/49/3 74/50/3 51/51/3
f 35/52/5 42/53/5 43/54/5
f 86/55/5 108/56/5 81/57/5
f 40/58/5 45/59/5 96/60/5
f 49/61/6 132/62/6 52/63/6
f 91/64/5 123/65/5 136/66/5
f 138/67/5 72/68/5 66/69/5
f 48/70/1 47/71/1 54/72/1
f 97/73/5 76/74/5 74/75/5
f 57/76/5 133/77/5 98/78/5
f 96/79/2 139/80/2 124/81/2
f 144/82/4 145/83/4 27/84/4
f 69/85/5 59/86/5 115/87/5
f 55/88/1 154/89/1 155/90/1
f 35/91/3 111/92/3 32/93/3
f 38/94/3 60/95/3 61/96/3
f 43/97/3 71/98/3 14/99/3
f 44/100/3 22/101/3 16/102/3
f 102/103/1 149/104/1 30/105/1
f 113/106/3 69/107/3 65/108/3
f 78/109/3 150/110/3 77/111/3
f 131/112/1 28/42/1 134/113/1
f 33/114/3 34/115/3 64/116/3
f 7/117/2 110/118/2 2/119/2
f 15/120/2 39/121/2 13/122/2
f 125/123/2 137/124/2 92/125/2
f 80/126/5 104/127/5 58/128/5
f 116/129/2 128/130/2 138/131/2
f 150/132/1 114/133/1 147/134/1
f 116/135/5 34/136/5 85/137/5
f 103/138/2 26/139/2 102/140/2
f 145/141/2 23/142/2 27/143/2
f 28/144/2 101/145/2 99/146/2
f 105/147/2 151/148/2 87/149/2
f 109/150/6 110/151/6 59/152/6
f 85/153/6 34/154/6 33/155/6
f 5/156/6 63/157/6 86/158/6
f 61/159/6 60/160/6 62/161/6
f 10/162/6 35/163/6 37/164/6
f 138/165/4 67/166/4 90/167/4
f 8/168/6 115/169/6 7/170/6
f 9/171/6 118/172/6 117/173/6
f 120/174/6 121/175/6 73/176/6
f 13/122/4 39/121/4 41/177/4
f 107/178/6 108/179/6 106/180/6
f 50/181/6 94/182/6 129/183/6
f 134/113/6 19/184/6 131/112/6
f 76/185/6 98/186/6 133/187/6
f 54/188/6 20/189/6 47/190/6
f 104/191/6 56/192/6 57/193/6
f 149/194/4 58/195/4 30/196/4
f 102/197/4 55/198/4 146/199/4
f 6/200/2 31/201/2 83/202/2
f 29/203/1 132/204/1 21/205/1
f 156/206/4 153/207/4 105/208/4
f 48/209/6 114/210/6 29/211/6
f 128/212/1 84/213/1 10/2/1
f 84/213/1 111/214/1 10/2/1
f 14/215/1 71/216/1 128/212/1
f 119/217/1 15/218/1 13/1/1
f 14/215/1 128/212/1 10/2/1
f 106/219/1 119/217/1 6/3/1
f 119/217/1 13/1/1 6/3/1
f 13/1/1 14/215/1 10/2/1
f 6/3/1 83/220/1 106/219/1
f 81/221/2 107/222/2 86/223/2
f 107/222/2 40/224/2 86/223/2
f 91/225/2 88/226/2 89/227/2
f 109/5/2 82/228/2 5/6/2
f 5/6/2 86/223/2 89/227/2
f 86/223/2 40/224/2 91/225/2
f 89/227/2 86/223/2 91/225/2
f 89/227/2 11/4/2 5/6/2
f 62/229/1 60/230/1 8/9/1
f 7/231/1 2/232/1 109/5/1
f 144/8/1 62/229/1 8/9/1
f 7/231/1 109/5/1 11/4/1
f 135/233/1 26/234/1 22/235/1
f 26/234/1 144/8/1 22/235/1
f 140/28/1 75/236/1 20/237/1
f 18/29/1 140/28/1 20/237/1
f 22/235/1 18/29/1 135/233/1
f 18/29/1 20/237/1 135/233/1
f 12/238/1 92/239/1 11/4/1
f 92/239/1 16/7/1 8/9/1
f 11/4/1 92/239/1 7/231/1
f 16/7/1 22/235/1 144/8/1
f 8/9/1 7/231/1 92/239/1
f 114/10/3 154/240/3 155/11/3
f 113/13/1 5/241/1 82/14/1
f 65/16/4 88/242/4 91/17/4
f 96/243/4 53/244/4 141/245/4
f 53/244/4 78/246/4 141/245/4
f 96/243/4 141/245/4 24/19/4
f 51/20/4 142/247/4 140/248/4
f 142/247/4 75/249/4 140/248/4
f 140/248/4 139/21/4 51/20/4
f 139/21/4 96/243/4 24/19/4
f 122/22/1 124/250/1 88/23/1
f 127/25/1 94/251/1 90/26/1
f 92/239/1 12/238/1 125/30/1
f 12/238/1 139/80/1 125/30/1
f 139/80/1 140/28/1 125/30/1
f 44/31/4 16/252/4 92/32/4
f 25/35/1 99/253/1 27/254/1
f 17/255/1 24/256/1 19/34/1
f 24/256/1 141/257/1 19/34/1
f 25/35/1 27/254/1 23/36/1
f 17/255/1 19/34/1 23/36/1
f 3/258/3 62/259/3 118/260/3
f 62/259/3 144/37/3 118/260/3
f 143/261/3 42/262/3 72/38/3
f 42/262/3 66/263/3 72/38/3
f 67/264/3 117/265/3 118/260/3
f 68/266/3 67/264/3 118/260/3
f 144/37/3 143/261/3 72/38/3
f 127/39/3 68/266/3 144/37/3
f 68/266/3 118/260/3 144/37/3
f 77/40/4 150/267/4 101/41/4
f 80/268/3 149/269/3 56/44/3
f 149/269/3 146/45/3 56/44/3
f 55/270/3 47/271/3 75/272/3
f 47/271/3 20/273/3 75/272/3
f 146/45/3 55/270/3 75/272/3
f 142/274/3 76/275/3 133/43/3
f 146/45/3 75/272/3 142/274/3
f 56/44/3 79/276/3 80/268/3
f 142/274/3 133/43/3 146/45/3
f 118/46/1 9/277/1 4/47/1
f 51/51/3 24/278/3 121/49/3
f 24/278/3 17/279/3 73/280/3
f 73/280/3 121/49/3 24/278/3
f 32/281/5 33/282/5 35/52/5
f 33/282/5 42/53/5 35/52/5
f 143/283/5 100/284/5 70/285/5
f 100/284/5 49/286/5 70/285/5
f 52/287/5 78/288/5 53/289/5
f 52/287/5 53/289/5 46/290/5
f 52/287/5 46/290/5 49/286/5
f 46/290/5 70/285/5 49/286/5
f 43/54/5 41/291/5 37/292/5
f 43/54/5 37/292/5 35/52/5
f 143/283/5 70/285/5 42/53/5
f 70/285/5 43/54/5 42/53/5
f 86/55/5 63/293/5 108/56/5
f 107/294/5 31/295/5 36/296/5
f 36/296/5 37/292/5 41/291/5
f 36/296/5 41/291/5 39/297/5
f 40/58/5 107/294/5 36/296/5
f 46/290/5 53/289/5 45/59/5
f 53/289/5 96/60/5 45/59/5
f 36/296/5 39/297/5 40/58/5
f 39/297/5 45/59/5 40/58/5
f 49/61/6 21/298/6 132/62/6
f 91/64/5 95/299/5 123/65/5
f 138/67/5 129/300/5 72/68/5
f 54/72/1 152/301/1 151/302/1
f 152/301/1 156/303/1 153/304/1
f 151/302/1 152/301/1 153/304/1
f 151/302/1 48/70/1 54/72/1
f 142/305/5 51/306/5 76/74/5
f 51/306/5 74/75/5 76/74/5
f 50/307/5 145/308/5 97/73/5
f 145/308/5 103/309/5 97/73/5
f 50/307/5 97/73/5 74/75/5
f 57/76/5 56/310/5 133/77/5
f 95/311/2 91/225/2 40/224/2
f 139/80/2 12/238/2 124/81/2
f 12/238/2 11/4/2 88/226/2
f 124/81/2 12/238/2 88/226/2
f 11/4/2 89/227/2 88/226/2
f 95/311/2 40/224/2 96/79/2
f 124/81/2 95/311/2 96/79/2
f 27/84/4 99/312/4 143/313/4
f 99/312/4 100/314/4 143/313/4
f 26/315/4 103/316/4 144/82/4
f 103/316/4 145/83/4 144/82/4
f 27/84/4 143/313/4 144/82/4
f 38/317/5 61/318/5 112/319/5
f 112/319/5 130/320/5 38/317/5
f 130/320/5 126/321/5 44/322/5
f 130/320/5 44/322/5 38/317/5
f 137/323/5 93/324/5 69/85/5
f 38/317/5 44/322/5 137/323/5
f 59/86/5 110/325/5 115/87/5
f 115/87/5 38/317/5 137/323/5
f 137/323/5 69/85/5 115/87/5
f 156/303/1 152/301/1 55/88/1
f 47/71/1 48/70/1 154/89/1
f 155/90/1 156/303/1 55/88/1
f 55/88/1 47/71/1 154/89/1
f 35/91/3 10/326/3 111/92/3
f 38/94/3 8/327/3 60/95/3
f 43/97/3 70/328/3 71/98/3
f 44/100/3 126/329/3 22/101/3
f 102/103/1 146/330/1 149/104/1
f 119/331/3 106/332/3 63/333/3
f 106/332/3 108/334/3 63/333/3
f 136/335/3 123/336/3 120/337/3
f 120/337/3 119/331/3 136/335/3
f 119/331/3 63/333/3 136/335/3
f 113/106/3 1/338/3 59/339/3
f 69/107/3 122/340/3 65/108/3
f 65/108/3 136/335/3 63/333/3
f 113/106/3 59/339/3 69/107/3
f 65/108/3 63/333/3 113/106/3
f 78/109/3 52/341/3 132/342/3
f 77/111/3 131/343/3 141/344/3
f 131/343/3 19/345/3 141/344/3
f 78/109/3 132/342/3 150/110/3
f 77/111/3 141/344/3 78/109/3
f 131/112/1 77/40/1 28/42/1
f 64/116/3 117/265/3 67/264/3
f 66/263/3 42/262/3 64/116/3
f 42/262/3 33/114/3 64/116/3
f 64/116/3 67/264/3 66/263/3
f 7/117/2 115/346/2 110/118/2
f 15/120/2 45/347/2 39/121/2
f 125/123/2 93/348/2 137/124/2
f 80/126/5 79/349/5 104/127/5
f 90/350/2 94/351/2 130/352/2
f 130/352/2 112/353/2 9/354/2
f 112/353/2 4/355/2 9/354/2
f 90/350/2 130/352/2 9/354/2
f 116/129/2 85/356/2 84/357/2
f 90/350/2 9/354/2 116/129/2
f 128/130/2 129/358/2 138/131/2
f 138/131/2 90/350/2 116/129/2
f 116/129/2 84/357/2 128/130/2
f 148/359/1 101/360/1 150/132/1
f 132/204/1 29/203/1 114/133/1
f 147/134/1 148/359/1 150/132/1
f 150/132/1 132/204/1 114/133/1
f 116/135/5 64/361/5 34/136/5
f 57/362/2 98/363/2 102/140/2
f 98/363/2 97/364/2 103/138/2
f 98/363/2 103/138/2 102/140/2
f 58/365/2 104/366/2 57/362/2
f 102/140/2 30/367/2 57/362/2
f 30/367/2 58/365/2 57/362/2
f 135/368/2 54/369/2 26/139/2
f 54/369/2 152/370/2 26/139/2
f 26/139/2 152/370/2 102/140/2
f 145/141/2 50/371/2 23/142/2
f 25/372/2 134/373/2 99/146/2
f 134/373/2 28/144/2 99/146/2
f 101/145/2 21/374/2 100/375/2
f 21/374/2 49/376/2 100/375/2
f 101/145/2 100/375/2 99/146/2
f 105/147/2 153/377/2 151/148/2
f 109/150/6 2/378/6 110/151/6
f 59/152/6 1/379/6 109/150/6
f 1/379/6 82/380/6 109/150/6
f 32/93/6 111/92/6 33/155/6
f 111/92/6 84/381/6 33/155/6
f 84/381/6 85/153/6 33/155/6
f 5/156/6 113/382/6 63/157/6
f 3/383/6 4/384/6 62/161/6
f 4/384/6 112/385/6 62/161/6
f 112/385/6 61/159/6 62/161/6
f 36/386/6 6/200/6 37/164/6
f 6/200/6 10/162/6 37/164/6
f 66/387/4 67/166/4 138/165/4
f 67/166/4 68/388/4 90/167/4
f 8/168/6 38/389/6 115/169/6
f 64/390/6 116/391/6 117/173/6
f 116/391/6 9/171/6 117/173/6
f 120/174/6 123/392/6 121/175/6
f 41/177/4 43/97/4 14/99/4
f 14/99/4 13/122/4 41/177/4
f 107/178/6 81/393/6 108/179/6
f 106/180/6 83/202/6 107/178/6
f 83/202/6 31/201/6 107/178/6
f 74/394/6 121/175/6 122/395/6
f 121/175/6 123/392/6 122/395/6
f 123/392/6 95/396/6 124/397/6
f 123/392/6 124/397/6 122/395/6
f 120/174/6 73/176/6 119/398/6
f 73/176/6 17/399/6 119/398/6
f 74/394/6 122/395/6 69/400/6
f 119/398/6 17/399/6 15/401/6
f 17/399/6 23/402/6 15/401/6
f 46/403/6 45/404/6 15/401/6
f 50/181/6 74/394/6 93/405/6
f 74/394/6 69/400/6 93/405/6
f 93/405/6 125/406/6 18/407/6
f 46/403/6 15/401/6 71/408/6
f 15/401/6 23/402/6 71/408/6
f 71/408/6 70/409/6 46/403/6
f 50/181/6 93/405/6 126/410/6
f 93/405/6 18/407/6 126/410/6
f 18/407/6 22/411/6 126/410/6
f 128/412/6 71/408/6 23/402/6
f 127/413/6 72/414/6 129/183/6
f 129/183/6 128/412/6 23/402/6
f 50/181/6 126/410/6 130/415/6
f 94/182/6 127/413/6 129/183/6
f 50/181/6 130/415/6 94/182/6
f 129/183/6 23/402/6 50/181/6
f 134/113/6 25/416/6 19/184/6
f 76/185/6 97/417/6 98/186/6
f 54/188/6 135/418/6 20/189/6
f 104/191/6 79/419/6 56/192/6
f 149/194/4 80/420/4 58/195/4
f 102/197/4 152/421/4 55/198/4
f 6/200/2 36/386/2 31/201/2
f 21/205/1 101/360/1 87/422/1
f 101/360/1 148/359/1 105/423/1
f 87/422/1 101/360/1 105/423/1
f 87/422/1 29/203/1 21/205/1
f 105/208/4 148/424/4 156/206/4
f 148/424/4 147/134/4 156/206/4
f 147/134/4 155/425/4 156/206/4
f 29/211/6 87/426/6 151/427/6
f 48/209/6 154/428/6 114/210/6
f 29/211/6 151/427/6 48/209/6

BIN
screenshot.2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

BIN
screenshot.3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 289 KiB

View File

@ -1,6 +1,6 @@
/**
* Deploy code to CDB
* Copyright (C) 2025 SaKeL
* 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
@ -29,7 +29,7 @@ try {
ref: 'master'
}
const response = await fetch('https://content.luanti.org/api/packages/SaKeL/x_enchanting/releases/new/', {
const response = await fetch('https://content.minetest.net/api/packages/SaKeL/x_enchanting/releases/new/', {
method: 'POST',
body: JSON.stringify(body),
headers: {

View File

@ -1,6 +1,6 @@
/**
* Run LUA diagnostics in continuous integration
* Copyright (C) 2025 SaKeL
* 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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,6 @@
---@diagnostic disable
--[[
X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2025 SaKeL
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
@ -17,13 +16,16 @@
License along with this library; if not, write to juraj.vajda@gmail.com
--]]
local S = core.get_translator(core.get_current_modname())
---@diagnostic disable-next-line
screwdriver = minetest.global_exists('screwdriver') and screwdriver --[[@as MtgScrewdriver]]
local S = minetest.get_translator(minetest.get_current_modname())
----
--- Table Node
----
core.register_node('x_enchanting:table', {
minetest.register_node('x_enchanting:table', {
description = S('Enchanting Table'),
short_description = S('Enchanting Table'),
drawtype = 'mesh',
@ -63,15 +65,15 @@ core.register_node('x_enchanting:table', {
light_source = 6,
---@param pos Vector
on_construct = function(pos)
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
meta:set_string('infotext', S('Enchanting Table'))
meta:set_string('owner', '')
inv:set_size('item', 1)
inv:set_size('trade', 1)
core.add_entity({ x = pos.x, y = pos.y + 0.7, z = pos.z }, 'x_enchanting:table_scroll')
core.get_node_timer(pos):start(5)
minetest.add_entity({ x = pos.x, y = pos.y + 0.7, z = pos.z }, 'x_enchanting:table_scroll')
minetest.get_node_timer(pos):start(5)
end,
---@param pos Vector
---@param placer ObjectRef | nil
@ -79,7 +81,7 @@ core.register_node('x_enchanting:table', {
---@param pointed_thing PointedThingDef
---@diagnostic disable-next-line: unused-local
after_place_node = function(pos, placer, itemstack, pointed_thing)
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
if not placer then
return
@ -100,34 +102,34 @@ core.register_node('x_enchanting:table', {
---@param pointed_thing? PointedThingDef
---@diagnostic disable-next-line: unused-local
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
local p_name = clicker:get_player_name()
if core.is_protected(pos, p_name) then
if minetest.is_protected(pos, p_name) then
return itemstack
end
core.sound_play('x_enchanting_scroll', {
minetest.sound_play('x_enchanting_scroll', {
gain = 0.3,
pos = pos,
max_hear_distance = 10
}, true)
-- bookshelfs
local bookshelfs = core.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 + 2, z = pos.z + 2 },
{ 'default:bookshelf', 'group:bookshelf' }
)
local inv = core.get_meta(pos):get_inventory()
local inv = minetest.get_meta(pos):get_inventory()
if not inv:is_empty('item') and inv:get_stack('item', 1):get_meta():get_int('is_enchanted') ~= 1 then
local item_stack = inv:get_stack('item', 1)
local data = XEnchanting:get_enchantment_data(
clicker,
#bookshelfs,
core.registered_tools[item_stack:get_name()]
minetest.registered_tools[item_stack:get_name()] or minetest.registered_craftitems[item_stack:get_name()]
)
local formspec = XEnchanting:get_formspec(pos, p_name, data)
@ -145,12 +147,12 @@ core.register_node('x_enchanting:table', {
---@return table | nil
---@diagnostic disable-next-line: unused-local
on_blast = function(pos, intensity)
if core.is_protected(pos, '') then
if minetest.is_protected(pos, '') then
return
end
local drops = {}
local inv = core.get_meta(pos):get_inventory()
local inv = minetest.get_meta(pos):get_inventory()
local stack_item = inv:get_stack('item', 1)
local stack_trade = inv:get_stack('trade', 1)
@ -163,7 +165,7 @@ core.register_node('x_enchanting:table', {
end
drops[#drops + 1] = 'x_enchanting:table'
core.remove_node(pos)
minetest.remove_node(pos)
return drops
end,
@ -174,11 +176,11 @@ core.register_node('x_enchanting:table', {
return false
end
local inv = core.get_meta(pos):get_inventory()
local inv = minetest.get_meta(pos):get_inventory()
return inv:is_empty('item')
and inv:is_empty('trade')
and not core.is_protected(pos, player:get_player_name())
and not minetest.is_protected(pos, player:get_player_name())
end,
---@diagnostic disable-next-line: unused-local
on_rotate = function(pos, node, user, mode, new_param2)
@ -189,10 +191,10 @@ core.register_node('x_enchanting:table', {
---@diagnostic disable-next-line: unused-local
on_timer = function(pos, elapsed)
-- entity
local table_scroll = core.get_objects_inside_radius(pos, 0.9)
local table_scroll = minetest.get_objects_inside_radius(pos, 0.9)
if #table_scroll == 0 then
core.add_entity({ x = pos.x, y = pos.y + 0.7, z = pos.z }, 'x_enchanting:table_scroll')
minetest.add_entity({ x = pos.x, y = pos.y + 0.7, z = pos.z }, 'x_enchanting:table_scroll')
end
local particlespawner_def = {
@ -212,7 +214,7 @@ core.register_node('x_enchanting:table', {
glow = 1
}
if core.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then
if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then
-- new syntax, after v5.6.0
particlespawner_def = {
amount = 50,
@ -243,10 +245,10 @@ core.register_node('x_enchanting:table', {
}
end
core.add_particlespawner(particlespawner_def)
minetest.add_particlespawner(particlespawner_def)
---bookshelfs
local bookshelfs = core.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 + 2, z = pos.z + 2 },
{ 'default:bookshelf', 'group:bookshelf' }
@ -267,8 +269,8 @@ core.register_node('x_enchanting:table', {
local rand2 = math.random(10, 500) / 100
local rand3 = math.random(50, 200) / 100
core.after(rand2, function()
core.add_particle({
minetest.after(rand2, function()
minetest.add_particle({
pos = pos_random,
velocity = { x = x, y = 2 - y, z = z },
acceleration = { x = 0, y = rand1, z = 0 },
@ -284,7 +286,7 @@ core.register_node('x_enchanting:table', {
end,
---@param pos Vector
on_destruct = function(pos)
for _, obj in ipairs(core.get_objects_inside_radius(pos, 0.9)) do
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 0.9)) do
if obj
and obj:get_luaentity()
and obj:get_luaentity().name == 'x_enchanting:table_scroll'
@ -306,14 +308,14 @@ core.register_node('x_enchanting:table', {
local is_enchanted = st_meta:get_int('is_enchanted')
if listname == 'item'
and core.get_item_group(st_name, 'enchantability') > 0
and minetest.get_item_group(st_name, 'enchantability') > 0
and is_enchanted ~= 1
then
return stack:get_count()
elseif listname == 'trade'
and (
st_name == 'default:mese_crystal'
or core.get_item_group(st_name, 'enchanting_trade') > 0
or minetest.get_item_group(st_name, 'enchanting_trade') > 0
)
and is_enchanted ~= 1
then
@ -336,7 +338,7 @@ core.register_node('x_enchanting:table', {
elseif listname == 'trade'
and (
st_name == 'default:mese_crystal'
or core.get_item_group(st_name, 'enchanting_trade') > 0
or minetest.get_item_group(st_name, 'enchanting_trade') > 0
)
then
return stack:get_count()
@ -362,7 +364,7 @@ core.register_node('x_enchanting:table', {
---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
on_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
local p_name = player:get_player_name()
local inv = meta:get_inventory()
local item_stack = inv:get_stack('item', 1)
@ -371,7 +373,7 @@ core.register_node('x_enchanting:table', {
if not inv:is_empty('item') and is_enchanted == 0 then
-- bookshelfs
local bookshelfs = core.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 + 2, z = pos.z + 2 },
{ 'default:bookshelf', 'group:bookshelf' }
@ -380,7 +382,7 @@ core.register_node('x_enchanting:table', {
local data = XEnchanting:get_enchantment_data(
player,
#bookshelfs,
core.registered_tools[item_stack:get_name()]
minetest.registered_tools[item_stack:get_name()] or minetest.registered_craftitems[item_stack:get_name()]
)
local formspec = XEnchanting:get_formspec(pos, p_name, data)
@ -398,7 +400,7 @@ core.register_node('x_enchanting:table', {
---@param player ObjectRef
---@diagnostic disable-next-line: unused-local
on_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = core.get_meta(pos)
local meta = minetest.get_meta(pos)
local p_name = player:get_player_name()
local inv = meta:get_inventory()
local item_stack = inv:get_stack('item', 1)
@ -407,7 +409,7 @@ core.register_node('x_enchanting:table', {
if not inv:is_empty('item') and is_enchanted == 0 then
-- bookshelfs
local bookshelfs = core.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 + 2, z = pos.z + 2 },
{ 'default:bookshelf', 'group:bookshelf' }
@ -416,7 +418,7 @@ core.register_node('x_enchanting:table', {
local data = XEnchanting:get_enchantment_data(
player,
#bookshelfs,
core.registered_tools[item_stack:get_name()]
minetest.registered_tools[item_stack:get_name()] or minetest.registered_craftitems[item_stack:get_name()]
)
local formspec = XEnchanting:get_formspec(pos, p_name, data)
@ -455,7 +457,7 @@ core.register_node('x_enchanting:table', {
return
end
local inv = core.get_meta(pos):get_inventory()
local inv = minetest.get_meta(pos):get_inventory()
if inv:is_empty('trade') or inv:is_empty('item') then
return
@ -485,10 +487,10 @@ core.register_node('x_enchanting:table', {
})
----
--- Entity (Scroll)
--- Entity - Scroll
----
core.register_entity('x_enchanting:table_scroll', {
minetest.register_entity('x_enchanting:table_scroll', {
initial_properties = {
visual = 'mesh',
mesh = 'x_enchanting_scroll.b3d',
@ -543,7 +545,7 @@ core.register_entity('x_enchanting:table_scroll', {
-- table
if self._tablechecktimer <= 0 then
self._tablechecktimer = 5
local node = core.get_node({ x = pos.x, y = pos.y - 0.7, z = pos.z })
local node = minetest.get_node({ x = pos.x, y = pos.y - 0.7, z = pos.z })
if node.name ~= 'x_enchanting:table' then
-- remove entity when no table under it
@ -554,7 +556,7 @@ core.register_entity('x_enchanting:table_scroll', {
-- player
if self._playerchecktimer <= 0 then
self._playerchecktimer = 1
local objects = core.get_objects_inside_radius(pos, 5)
local objects = minetest.get_objects_inside_radius(pos, 5)
-- inital value
local shortest_distance = 10
@ -587,7 +589,7 @@ core.register_entity('x_enchanting:table_scroll', {
self._scroll_closed = false
self.object:set_animation(unpack(XEnchanting.scroll_animations.scroll_open))
core.sound_play('x_enchanting_scroll', {
minetest.sound_play('x_enchanting_scroll', {
gain = 0.3,
pos = pos,
max_hear_distance = 10
@ -596,7 +598,7 @@ core.register_entity('x_enchanting:table_scroll', {
self._scroll_closed = true
self.object:set_animation(unpack(XEnchanting.scroll_animations.scroll_close))
core.sound_play('x_enchanting_scroll', {
minetest.sound_play('x_enchanting_scroll', {
gain = 0.3,
pos = pos,
max_hear_distance = 10
@ -607,7 +609,7 @@ core.register_entity('x_enchanting:table_scroll', {
-- rotation
if self._player and self._player:get_pos() then
local direction = vector.direction(pos, self._player:get_pos())
self.object:set_yaw(core.dir_to_yaw(direction))
self.object:set_yaw(minetest.dir_to_yaw(direction))
else
self.object:set_rotation({
x = self._last_rotation.x,
@ -633,17 +635,17 @@ core.register_entity('x_enchanting:table_scroll', {
-- Recipe
---
if core.get_modpath('xdecor') or core.get_modpath('enchanting') then
core.register_craft({
if minetest.get_modpath('xdecor') then
minetest.register_craft({
output = 'x_enchanting:table',
recipe = {
{ 'default:book', '', '' },
{ 'default:diamond', 'xdecor:enchantment_table', 'default:diamond' },
{ 'default:diamond', 'default:obsidian', 'default:diamond' },
{ 'default:obsidian', 'default:obsidian', 'default:obsidian' }
}
})
else
core.register_craft({
minetest.register_craft({
output = 'x_enchanting:table',
recipe = {
{ '', 'default:book', '' },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

View File

@ -94,6 +94,7 @@
---@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_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 itemstring_with_palette fun(item: string | ItemStack, palette_index: integer): string returns an item string. Creates an item string which contains palette index information for hardware colorization. You can use the returned string as an output in a craft recipe. `item`: the item stack which becomes colored. Can be in string, table and native form. `palette_index`: this index is added to the item stack
---@field get_player_information fun(player_name: string): table Table containing information about a player
---Minetest settings

View File

@ -20,6 +20,7 @@
---@field walkable boolean If true, objects collide with node.
---@field after_dig_node fun(pos: Vector, oldnode: NodeDef, oldmetadata: table, digger: ObjectRef): nil oldmetadata is in table format. Called after destructing node when node was dug using minetest.node_dig / minetest.dig_node., default: nil
---@field paramtype2 string
---@field palette string Image
---@field can_dig fun(pos: Vector, player?: ObjectRef): boolean | nil Returns true if node can be dug, or false if not.default: nil
---@field on_rotate fun(pos: Vector, node: table, user: ObjectRef, mode: table, new_param2: string): boolean Only for screwdriver mod.
---@field on_construct fun(pos: Vector): nil Node constructor; called after adding node. Can set up metadata and stuff like that. Not called for bulk node placement (i.e. schematics and VoxelManip). default: nil

View File

@ -6,7 +6,7 @@
---@field roman_numbers table<number, string> Convert Arabic numbers to Roman numbers
---@field enchantment_defs table<'sharpness' | 'fortune' | 'unbreaking' | 'efficiency' | 'silk_touch' | 'curse_of_vanishing' | 'knockback', EnchantmentDef>
---@field has_tool_group fun(self: XEnchanting, name: string): string | boolean Check if tool has one of the known tool groups, returns `false` otherwise.
---@field set_tool_enchantability fun(self: XEnchanting, tool_def: ItemDef): nil Sets `enchantibility` group and values from base table (`XEnchanting.tools_enchantability`) to all registered tools (atching known group names). If tool has already `enchantibility` group defined it will take the defined value insted.
---@field set_enchantability fun(self: XEnchanting, tool_def: ItemDef): nil Sets `enchantibility` group and values from base table (`XEnchanting.tools_enchantability`) to all registered tools (atching known group names). If tool has already `enchantibility` group defined it will take the defined value insted.
---@field get_enchanted_tool_capabilities fun(self: XEnchanting, tool_def: ItemDef, enchantments: Enchantment[]): ToolCapabilitiesDef Applies enchantments to item tool capabilities.
---@field set_enchanted_tool fun(self: XEnchanting, pos: Vector, itemstack: ItemStack, level: number, player_name: string): nil Set choosen enchantment and its modified tool capabilities to itemstack and `item` inventory. This will also get new `randomseed`.
---@field get_enchantment_data fun(self: XEnchanting, player: ObjectRef, nr_of_bookshelfs: number, tool_def: ItemDef): EnchantmentData Algoritm to get aplicable random enchantments.

329
writing_table.lua Normal file
View File

@ -0,0 +1,329 @@
screwdriver = minetest.global_exists('screwdriver') and screwdriver --[[@as MtgScrewdriver]]
local S = minetest.get_translator(minetest.get_current_modname())
----
--- Table Node
----
minetest.register_node('x_enchanting:writing_table', {
description = S('Writing Table'),
short_description = S('Writing Table'),
---top, bottom, sides...front
tiles = {
'x_enchanting_writing_table_top.png',
'x_enchanting_writing_table_bottom.png',
'x_enchanting_writing_table_side.png',
'x_enchanting_writing_table_side.png',
'x_enchanting_writing_table_side.png',
'x_enchanting_writing_table_front.png'
},
paramtype = 'light',
paramtype2 = 'facedir',
walkable = true,
wield_scale = { x = 2, y = 2, z = 2 },
sounds = {
footstep = {
name = 'x_enchanting_scroll',
gain = 0.2
},
dug = {
name = 'x_enchanting_scroll',
gain = 1.0
},
place = {
name = 'x_enchanting_scroll',
gain = 1.0
}
},
is_ground_content = false,
groups = { choppy = 2, oddly_breakable_by_hand = 2, flammable = 2 },
mod_origin = 'x_enchanting',
---@param pos Vector
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
meta:set_string('infotext', S('Writing Table'))
meta:set_string('owner', '')
inv:set_size('item', 1)
inv:set_size('sacrifice', 1)
inv:set_size('result', 1)
inv:set_size('trade', 1)
end,
---@param pos Vector
---@param placer ObjectRef | nil
---@param itemstack ItemStack
---@param pointed_thing PointedThingDef
after_place_node = function(pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
if not placer then
return
end
local player_name = placer:get_player_name()
local props = {
player_name = player_name
}
meta:set_string('owner', player_name)
meta:set_string('infotext', S('Writing Table') .. ' (' .. S('owned by') .. ' ' .. player_name .. ')')
local formspec = XEnchanting:get_formspec_writing_table(pos, props)
meta:set_string('formspec', formspec)
end,
---@param pos Vector
---@param node NodeDef
---@param clicker ObjectRef
---@param itemstack ItemStack
---@param pointed_thing? PointedThingDef
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local p_name = clicker:get_player_name()
local props = {
player_name = p_name,
inv = inv
}
if minetest.is_protected(pos, p_name) then
return itemstack
end
minetest.sound_play('x_enchanting_scroll', {
gain = 0.3,
pos = pos,
max_hear_distance = 10
}, true)
local data = XEnchanting:get_writing_table_total_data(props)
props.data = data
local formspec = XEnchanting:get_formspec_writing_table(pos, props)
meta:set_string('formspec', formspec)
return itemstack
end,
---@param pos Vector
---@param intensity? number
---@return table | nil
on_blast = function(pos, intensity)
if minetest.is_protected(pos, '') then
return
end
local drops = {}
local inv = minetest.get_meta(pos):get_inventory()
local stack_item = inv:get_stack('item', 1)
local stack_sacrifice = inv:get_stack('sacrifice', 1)
local stack_result = inv:get_stack('result', 1)
local stack_trade = inv:get_stack('trade', 1)
if not stack_item:is_empty() then
drops[#drops + 1] = stack_item:to_table()
end
if not stack_sacrifice:is_empty() then
drops[#drops + 1] = stack_sacrifice:to_table()
end
if not stack_result:is_empty() then
drops[#drops + 1] = stack_result:to_table()
end
if not stack_trade:is_empty() then
drops[#drops + 1] = stack_trade:to_table()
end
drops[#drops + 1] = 'x_enchanting:writing_table'
minetest.remove_node(pos)
return drops
end,
---@param pos Vector
---@param player? ObjectRef
can_dig = function(pos, player)
if not player then
return false
end
local inv = minetest.get_meta(pos):get_inventory()
return inv:is_empty('item')
and inv:is_empty('sacrifice')
and inv:is_empty('result')
and inv:is_empty('trade')
and not minetest.is_protected(pos, player:get_player_name())
end,
on_rotate = function(pos, node, user, mode, new_param2)
return false
end,
---@param pos Vector
---@param listname string
---@param index number
---@param stack ItemStack
---@param player ObjectRef
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
print('allow_metadata_inventory_put')
local st_name = stack:get_name()
local st_meta = stack:get_meta()
if listname == 'result' then
return 0
end
if listname == 'item'
and (st_meta:get_int('is_enchanted') > 0 or minetest.get_item_group(st_name, 'scroll') > 0)
then
return stack:get_count()
elseif listname == 'sacrifice'
and st_meta:get_int('is_enchanted') > 0
and minetest.get_item_group(st_name, 'scroll') > 0
then
return stack:get_count()
elseif listname == 'trade'
and (
st_name == 'default:mese_crystal'
or minetest.get_item_group(st_name, 'enchanting_trade') > 0
)
then
return stack:get_count()
end
return 0
end,
---@param pos Vector
---@param listname string
---@param index number
---@param stack ItemStack
---@param player ObjectRef
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
print('allow_metadata_inventory_take')
local st_name = stack:get_name()
if listname == 'item' then
return stack:get_count()
elseif listname == 'sacrifice' then
return stack:get_count()
elseif listname == 'result' then
return stack:get_count()
elseif listname == 'trade'
and (
st_name == 'default:mese_crystal'
or minetest.get_item_group(st_name, 'enchanting_trade') > 0
)
then
return stack:get_count()
end
return 0
end,
---@param pos Vector
---@param from_list string
---@param from_index number
---@param to_list string
---@param to_index number
---@param count number
---@param player ObjectRef
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
print('allow_metadata_inventory_move')
print('allow_metadata_inventory_move')
print('from_list', from_index, from_list)
print('to_list', to_index, to_list)
if (to_list == 'item' or to_list == 'sacrifice')
and (from_list == 'item' or from_list == 'sacrifice')
then
return count
end
return 0
end,
---@param pos Vector
---@param listname string
---@param index number
---@param stack ItemStack
---@param player ObjectRef
on_metadata_inventory_put = function(pos, listname, index, stack, player)
print('on_metadata_inventory_put')
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local props = {
player_name = player:get_player_name(),
inv = inv
}
local data = XEnchanting:get_writing_table_total_data(props)
props.data = data
local formspec = XEnchanting:get_formspec_writing_table(pos, props)
meta:set_string('formspec', formspec)
end,
---@param pos Vector
---@param listname string
---@param index number
---@param stack ItemStack
---@param player ObjectRef
on_metadata_inventory_take = function(pos, listname, index, stack, player)
print('on_metadata_inventory_take')
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if listname == 'result' then
inv:set_stack('item', 1, ItemStack(''))
inv:set_stack('sacrifice', 1, ItemStack(''))
inv:set_stack('result', 1, ItemStack(''))
return
end
local props = {
player_name = player:get_player_name(),
inv = inv
}
local data = XEnchanting:get_writing_table_total_data(props)
props.data = data
local formspec = XEnchanting:get_formspec_writing_table(pos, props)
meta:set_string('formspec', formspec)
end,
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
print('on_metadata_inventory_move')
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local props = {
player_name = player:get_player_name(),
inv = inv
}
local data = XEnchanting:get_writing_table_total_data(props)
props.data = data
local formspec = XEnchanting:get_formspec_writing_table(pos, props)
meta:set_string('formspec', formspec)
end,
-- form receive fields
---@param pos Vector
---@param formname string
---@param fields table
---@param sender ObjectRef
on_receive_fields = function(pos, formname, fields, sender)
end
})
-- Scroll Item
minetest.register_craftitem('x_enchanting:scroll_item', {
description = S('Scroll'),
short_description = S('Scroll'),
inventory_image = 'x_enchanting_scroll_item.png^[colorize:#8F00FF:60',
wield_image = 'x_enchanting_scroll_item.png^[transformFXR90^[colorize:#8F00FF:60',
groups = { scroll = 1, flammable = 3 },
stack_max = 1
})