Compare commits

...

14 Commits

27 changed files with 894 additions and 67 deletions

15
.gitattributes vendored Normal file
View File

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

View File

@ -1,7 +1,7 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999 Version 2.1, February 1999
Copyright (C) 2022 SaKeL <juraj.vajda@gmail.com> Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.

View File

@ -18,8 +18,6 @@ Adds Enchanting Mechanics and API.
* mesh node model * mesh node model
* mesh entity model and animations * mesh entity model and animations
NOTE: item inventory/wield image will not be adjusted until this feature is supported by MT engine, see: https://github.com/minetest/minetest/issues/5686
## How To ## How To
### Enchanting Setup ### Enchanting Setup
@ -178,6 +176,7 @@ end
## Optional Dependencies ## Optional Dependencies
- xdecor (adjusts conflicting recipe) - xdecor (adjusts conflicting recipe)
- item_drop (make sure fortune will execute before item_drop mod overrides `handle_node_drops`)
## License: ## License:
@ -187,7 +186,7 @@ GNU Lesser General Public License v2.1 or later (see included LICENSE file)
### Textures ### Textures
**CC BY-SA 4.0, Pixel Perfection by XSSheep**, https://minecraft.curseforge.com/projects/pixel-perfection-freshly-updated **CC-BY-SA-4.0, Pixel Perfection by XSSheep**, https://minecraft.curseforge.com/projects/pixel-perfection-freshly-updated
- x_enchanting_symbol_1.png - x_enchanting_symbol_1.png
- x_enchanting_symbol_2.png - x_enchanting_symbol_2.png
@ -227,11 +226,11 @@ GNU Lesser General Public License v2.1 or later (see included LICENSE file)
- x_enchanting_scroll_mesh.png -- Derived from a texture TumeniNodes (CC BY-SA 3.0) - x_enchanting_scroll_mesh.png -- Derived from a texture TumeniNodes (CC BY-SA 3.0)
- x_enchanting_scroll_particle.png - x_enchanting_scroll_particle.png
- x_enchanting_table.png - x_enchanting_table.png
- x_enchanting_gui_slot_bg.png -- Derived from texture Pixel Perfection by XSSheep (CC BY-SA 4.0) - 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_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_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_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) - x_enchanting_gui_hb_bg.png -- Derived from texture Pixel Perfection by XSSheep (CC-BY-SA-4.0)
### Models ### Models

531
api.lua
View File

@ -1,6 +1,6 @@
--[[ --[[
X Enchanting. Adds Enchanting Mechanics and API. X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2022 SaKeL <juraj.vajda@gmail.com> Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -80,8 +80,12 @@ XEnchanting = {
}, },
weight = 10, weight = 10,
groups = { groups = {
'sword' 'sword',
} 'book',
'scroll'
},
multiplier_from_scroll = 1,
multiplier_from_item = 1
}, },
looting = { looting = {
name = S('Looting'), name = S('Looting'),
@ -99,8 +103,12 @@ XEnchanting = {
}, },
weight = 2, weight = 2,
groups = { groups = {
'sword' 'sword',
} 'book',
'scroll'
},
multiplier_from_scroll = 2,
multiplier_from_item = 4
}, },
fortune = { fortune = {
name = S('Fortune'), name = S('Fortune'),
@ -120,9 +128,13 @@ XEnchanting = {
groups = { groups = {
'pickaxe', 'pickaxe',
'shovel', 'shovel',
'axe' 'axe',
'book',
'scroll'
}, },
incompatible = { 'silk_touch' } incompatible = { 'silk_touch' },
multiplier_from_scroll = 2,
multiplier_from_item = 4
}, },
unbreaking = { unbreaking = {
name = S('Unbreaking'), name = S('Unbreaking'),
@ -140,7 +152,9 @@ XEnchanting = {
}, },
weight = 5, weight = 5,
-- all applicable -- all applicable
groups = nil groups = nil,
multiplier_from_scroll = 1,
multiplier_from_item = 2
}, },
efficiency = { efficiency = {
name = S('Efficiency'), name = S('Efficiency'),
@ -150,7 +164,7 @@ XEnchanting = {
[2] = { 11, 61 }, [2] = { 11, 61 },
[3] = { 21, 71 }, [3] = { 21, 71 },
[4] = { 31, 81 }, [4] = { 31, 81 },
[5] = { 41, 91 }, -- [5] = { 41, 91 },
}, },
-- level definition, `level = percentage increase` -- level definition, `level = percentage increase`
level_def = { level_def = {
@ -158,14 +172,18 @@ XEnchanting = {
[2] = 30, [2] = 30,
[3] = 35, [3] = 35,
[4] = 40, [4] = 40,
[5] = 45, -- [5] = 45,
}, },
weight = 10, weight = 10,
groups = { groups = {
'pickaxe', 'pickaxe',
'shovel', 'shovel',
'axe' 'axe',
} 'book',
'scroll'
},
multiplier_from_scroll = 1,
multiplier_from_item = 1
}, },
silk_touch = { silk_touch = {
name = S('Silk Touch'), name = S('Silk Touch'),
@ -180,9 +198,13 @@ XEnchanting = {
groups = { groups = {
'pickaxe', 'pickaxe',
'shovel', 'shovel',
'axe' 'axe',
'book',
'scroll'
}, },
incompatible = { 'fortune' } incompatible = { 'fortune' },
multiplier_from_scroll = 4,
multiplier_from_item = 8
}, },
curse_of_vanishing = { curse_of_vanishing = {
name = S('Curse of Vanishing'), name = S('Curse of Vanishing'),
@ -195,7 +217,9 @@ XEnchanting = {
weight = 1, weight = 1,
secondary = true, secondary = true,
-- all applicable -- all applicable
groups = nil groups = nil,
multiplier_from_scroll = 4,
multiplier_from_item = 8
}, },
knockback = { knockback = {
name = S('Knockback'), name = S('Knockback'),
@ -210,8 +234,12 @@ XEnchanting = {
}, },
weight = 5, weight = 5,
groups = { groups = {
'sword' 'sword',
} 'book',
'scroll'
},
multiplier_from_scroll = 1,
multiplier_from_item = 2
}, },
power = { power = {
-- Increases arrow damage. -- Increases arrow damage.
@ -234,8 +262,12 @@ XEnchanting = {
}, },
weight = 10, weight = 10,
groups = { groups = {
'bow' 'bow',
} 'book',
'scroll'
},
multiplier_from_scroll = 1,
multiplier_from_item = 1
}, },
punch = { punch = {
-- Increases arrow knockback. -- Increases arrow knockback.
@ -252,8 +284,12 @@ XEnchanting = {
}, },
weight = 2, weight = 2,
groups = { groups = {
'bow' 'bow',
} 'book',
'scroll'
},
multiplier_from_scroll = 2,
multiplier_from_item = 4
}, },
infinity = { infinity = {
-- Prevents regular arrows from being consumed when shot. -- Prevents regular arrows from being consumed when shot.
@ -270,8 +306,12 @@ XEnchanting = {
weight = 1, weight = 1,
secondary = true, secondary = true,
groups = { groups = {
'bow' 'bow',
} 'book',
'scroll'
},
multiplier_from_scroll = 4,
multiplier_from_item = 8
}, },
}, },
form_context = {}, form_context = {},
@ -306,6 +346,17 @@ local function get_table_length(table)
return length return length
end end
---Find element v of t satisfying f(v)
local function tableFind(t, f)
for _, v in ipairs(t) do
if f(v) then
return v
end
end
return nil
end
---@diagnostic disable-next-line: unused-local ---@diagnostic disable-next-line: unused-local
function XEnchanting.has_tool_group(self, name) function XEnchanting.has_tool_group(self, name)
if minetest.get_item_group(name, 'pickaxe') > 0 then if minetest.get_item_group(name, 'pickaxe') > 0 then
@ -318,12 +369,14 @@ function XEnchanting.has_tool_group(self, name)
return 'sword' return 'sword'
elseif minetest.get_item_group(name, 'bow') > 0 then elseif minetest.get_item_group(name, 'bow') > 0 then
return 'bow' return 'bow'
elseif minetest.get_item_group(name, 'book') > 0 then
return 'book'
end end
return false return false
end end
function XEnchanting.set_tool_enchantability(self, tool_def) function XEnchanting.set_enchantability(self, tool_def)
if minetest.get_item_group(tool_def.name, 'enchantability') > 0 then if minetest.get_item_group(tool_def.name, 'enchantability') > 0 then
-- enchantability is already set, we dont need to override the item -- enchantability is already set, we dont need to override the item
return return
@ -508,17 +561,28 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
local data = self.form_context[player_name].data local data = self.form_context[player_name].data
if not data then if not data then
minetest.log('warning', '[set_enchanted_tool] no data from form context found.')
return return
end 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 capabilities = data.slots[level].tool_cap_data
local description = data.slots[level].descriptions.enchantments_desc local description = data.slots[level].descriptions.enchantments_desc
local final_enchantments = data.slots[level].final_enchantments local final_enchantments = data.slots[level].final_enchantments
local inv = minetest.get_meta(pos):get_inventory() local inv = minetest.get_meta(pos):get_inventory()
local tool_def = minetest.registered_tools[itemstack:get_name()]
local node_meta = minetest.get_meta(pos) local node_meta = minetest.get_meta(pos)
if not tool_def then if not tool_def then
minetest.log(
'warning',
'[set_enchanted_tool] no tool definition found in registered_tools/registered_craftitems.'
)
return return
end end
@ -535,14 +599,38 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
} }
end 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('description', itemstack:get_description() .. '\n' .. description)
stack_meta:set_string('short_description', S('Enchanted') .. ' ' .. itemstack:get_short_description()) stack_meta:set_string('short_description', S('Enchanted') .. ' ' .. itemstack:get_short_description())
stack_meta:set_int('is_enchanted', 1) stack_meta:set_int('is_enchanted', 1)
stack_meta:set_string('x_enchanting', minetest.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)')
end
if tool_def and tool_def.inventory_overlay and tool_def.inventory_overlay ~= '' then
stack_meta:set_string('inventory_overlay', tool_def.inventory_overlay .. '^((' .. tool_def.inventory_overlay .. '^[contrast:127:127)^[mask:x_enchanting_glint.png^[opacity:80)')
end
if tool_def and tool_def.wield_image and tool_def.wield_image ~= '' then
stack_meta:set_string('wield_image', tool_def.wield_image .. '^((' .. tool_def.wield_image .. '^[contrast:127:127)^[mask:x_enchanting_glint.png^[opacity:80)')
end
if tool_def and tool_def.wield_overlay and tool_def.wield_overlay ~= '' then
stack_meta:set_string('wield_overlay', tool_def.wield_overlay .. '^((' .. tool_def.wield_overlay .. '^[contrast:127:127)^[mask:x_enchanting_glint.png^[opacity:80)')
end
inv:set_stack('item', 1, itemstack) inv:set_stack('item', 1, itemstack)
-- set new trade ItemStack
local trade_stack = inv:get_stack('trade', 1) local trade_stack = inv:get_stack('trade', 1)
trade_stack:take_item(level) trade_stack:take_item(level)
inv:set_stack('trade', 1, trade_stack) inv:set_stack('trade', 1, trade_stack)
@ -550,9 +638,11 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
-- set new seed -- set new seed
self.player_seeds[player_name] = self:get_randomseed() self.player_seeds[player_name] = self:get_randomseed()
-- update node formspec
local formspec = self:get_formspec(pos, player_name) local formspec = self:get_formspec(pos, player_name)
node_meta:set_string('formspec', formspec) node_meta:set_string('formspec', formspec)
-- play sound
minetest.sound_play('x_enchanting_enchant', { minetest.sound_play('x_enchanting_enchant', {
gain = 0.3, gain = 0.3,
pos = pos, pos = pos,
@ -612,6 +702,48 @@ function XEnchanting.set_enchanted_tool(self, pos, itemstack, level, player_name
minetest.add_particlespawner(particlespawner_def) minetest.add_particlespawner(particlespawner_def)
end 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) function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_def)
local p_name = player:get_player_name() local p_name = player:get_player_name()
local randomseed = self.player_seeds[p_name] or self:get_randomseed() local randomseed = self.player_seeds[p_name] or self:get_randomseed()
@ -767,11 +899,17 @@ function XEnchanting.get_enchantment_data(self, player, nr_of_bookshelfs, tool_d
table.remove(possible_enchantments, idx) table.remove(possible_enchantments, idx)
end end
end end
else else
local probability = (probability_level + 1) / 50 local probability = (probability_level + 1) / 50
table.insert(final_enchantments, rand_ench) local alreadyInTable = tableFind(final_enchantments, function(value)
return value.id == rand_ench.id
end)
if not alreadyInTable then
table.insert(final_enchantments, rand_ench)
end
table.remove(possible_enchantments, rand_ench_idx) table.remove(possible_enchantments, rand_ench_idx)
for idx, value in pairs(possible_enchantments) do for idx, value in pairs(possible_enchantments) do
@ -933,3 +1071,338 @@ function XEnchanting.get_formspec(self, pos, player_name, data)
return table.concat(formspec, '') return table.concat(formspec, '')
end end
function XEnchanting.get_writing_table_total_data(self, props)
local inv = props.inv
-- item
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
print('enchantments_sacrifice', dump(enchantments_sacrifice))
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
}
if stack_sacrifice:is_empty() or stack_item:is_empty() then
result_data.show_total_cost = 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
-- 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
result_data.total_cost = result_data.total_cost + enchantment_defs_for_group.writing_table_cost
-- 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
-- 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
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
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.

View File

@ -43,24 +43,24 @@ pipelines:
- nvm install v17.2.0 - nvm install v17.2.0
- npm i -g npm@8 - npm i -g npm@8
- npm ci - npm ci
- parallel: # - parallel:
- step: - step:
name: Lua Check name: Lua Check
script: script:
- apt-get update - apt-get update
- apt-get -y install lua5.1 - apt-get -y install lua5.1
- apt-get -y install luarocks - apt-get -y install luarocks
- luarocks install luacheck - luarocks install luacheck
- luacheck . - luacheck .
- step: # - step:
name: Lua Diagnostics # name: Lua Diagnostics
caches: # caches:
- node-modules # - node-modules
- npm # - npm
- nvm # - nvm
script: # script:
- nvm use v17.2.0 # - nvm use v17.2.0
- npm run lua-diagnostics # - npm run lua-diagnostics
- step: - step:
name: Deploy to ContentDB name: Deploy to ContentDB
caches: caches:

View File

@ -1,6 +1,6 @@
--[[ --[[
X Enchanting. Adds Enchanting Mechanics and API. X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2022 SaKeL <juraj.vajda@gmail.com> Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -21,6 +21,7 @@ local mod_start_time = minetest.get_us_time()
dofile(path .. '/api.lua') dofile(path .. '/api.lua')
dofile(path .. '/table.lua') dofile(path .. '/table.lua')
dofile(path .. '/writing_table.lua')
---Check if string X starts with string Y ---Check if string X starts with string Y
---@param str string ---@param str string
@ -34,7 +35,14 @@ minetest.register_on_mods_loaded(function()
-- Tools override -- Tools override
for name, tool_def in pairs(minetest.registered_tools) do for name, tool_def in pairs(minetest.registered_tools) do
if XEnchanting:has_tool_group(name) then if XEnchanting:has_tool_group(name) then
XEnchanting:set_tool_enchantability(tool_def) XEnchanting:set_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
end end

View File

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

View File

@ -1,6 +1,6 @@
/** /**
* Deploy code to CDB * Deploy code to CDB
* Copyright (C) 2022 SaKeL <juraj.vajda@gmail.com> * Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public

View File

@ -1,6 +1,6 @@
/** /**
* Run LUA diagnostics in continuous integration * Run LUA diagnostics in continuous integration
* Copyright (C) 2022 SaKeL <juraj.vajda@gmail.com> * Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public

View File

@ -1,6 +1,6 @@
--[[ --[[
X Enchanting. Adds Enchanting Mechanics and API. X Enchanting. Adds Enchanting Mechanics and API.
Copyright (C) 2022 SaKeL <juraj.vajda@gmail.com> Copyright (C) 2023 SaKeL <juraj.vajda@gmail.com>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -31,6 +31,7 @@ minetest.register_node('x_enchanting:table', {
drawtype = 'mesh', drawtype = 'mesh',
mesh = 'x_enchanting_table.obj', mesh = 'x_enchanting_table.obj',
tiles = { 'x_enchanting_table.png' }, tiles = { 'x_enchanting_table.png' },
use_texture_alpha = 'clip',
paramtype = 'light', paramtype = 'light',
paramtype2 = 'facedir', paramtype2 = 'facedir',
walkable = true, walkable = true,
@ -128,7 +129,7 @@ minetest.register_node('x_enchanting:table', {
local data = XEnchanting:get_enchantment_data( local data = XEnchanting:get_enchantment_data(
clicker, clicker,
#bookshelfs, #bookshelfs,
minetest.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) local formspec = XEnchanting:get_formspec(pos, p_name, data)
@ -381,7 +382,7 @@ minetest.register_node('x_enchanting:table', {
local data = XEnchanting:get_enchantment_data( local data = XEnchanting:get_enchantment_data(
player, player,
#bookshelfs, #bookshelfs,
minetest.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) local formspec = XEnchanting:get_formspec(pos, p_name, data)
@ -417,7 +418,7 @@ minetest.register_node('x_enchanting:table', {
local data = XEnchanting:get_enchantment_data( local data = XEnchanting:get_enchantment_data(
player, player,
#bookshelfs, #bookshelfs,
minetest.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) local formspec = XEnchanting:get_formspec(pos, p_name, data)
@ -486,7 +487,7 @@ minetest.register_node('x_enchanting:table', {
}) })
---- ----
--- Entity (Scroll) --- Entity - Scroll
---- ----
minetest.register_entity('x_enchanting:table_scroll', { minetest.register_entity('x_enchanting:table_scroll', {

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 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 handle_node_drops fun(pos: Vector, drops: string[], digger: ObjectRef) `drops`: list of itemstrings. Handles drops from nodes after digging: Default action is to put them into digger's inventory. Can be overridden to get different functionality (e.g. dropping items on ground)
---@field register_on_dieplayer fun(func: fun(player: ObjectRef, reason?: string)): nil Called when a player dies. `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange ---@field register_on_dieplayer fun(func: fun(player: ObjectRef, reason?: string)): nil Called when a player dies. `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange
---@field register_on_player_hpchange fun(func: fun(player, hp_change, reason), modifier): number Called when the player gets damaged or healed. `player`: ObjectRef of the player. `hp_change`: the amount of change. Negative when it is damage.. `reason`: a PlayerHPChangeReason table.. The `type` field will have one of the following values: `set_hp`: A mod or the engine called `set_hp` without giving a type - use this for custom damage types.. `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. `fall`, `node_damage`: `damage_per_second` from a neighbouring node. `reason.node` will hold the node name or nil. `drown` `respawn`. Any of the above types may have additional fields from mods. `reason.from` will be `mod` or `engine`. `modifier`: when true, the function should return the actual `hp_change`. Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. Modifiers can return true as a second argument to stop the execution of further functions. Non-modifiers receive the final HP change calculated by the modifiers. ---@field register_on_player_hpchange fun(func: fun(player, hp_change, reason), modifier): number Called when the player gets damaged or healed. `player`: ObjectRef of the player. `hp_change`: the amount of change. Negative when it is damage.. `reason`: a PlayerHPChangeReason table.. The `type` field will have one of the following values: `set_hp`: A mod or the engine called `set_hp` without giving a type - use this for custom damage types.. `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. `fall`, `node_damage`: `damage_per_second` from a neighbouring node. `reason.node` will hold the node name or nil. `drown` `respawn`. Any of the above types may have additional fields from mods. `reason.from` will be `mod` or `engine`. `modifier`: when true, the function should return the actual `hp_change`. Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. Modifiers can return true as a second argument to stop the execution of further functions. Non-modifiers receive the final HP change calculated by the modifiers.
---@field 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 ---@field get_player_information fun(player_name: string): table Table containing information about a player
---Minetest settings ---Minetest settings

View File

@ -20,6 +20,7 @@
---@field walkable boolean If true, objects collide with node. ---@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 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 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 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_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 ---@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 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 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 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 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 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. ---@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
})