2020-10-27 16:37:25 +01:00
local modpath = minetest.get_modpath ( " mcl_enchanting " )
2020-12-14 14:08:55 +01:00
local S = minetest.get_translator ( " mcl_enchanting " )
2020-10-27 16:37:25 +01:00
mcl_enchanting = {
book_offset = vector.new ( 0 , 0.75 , 0 ) ,
2020-11-25 12:47:27 +01:00
book_animations = { [ " close " ] = 1 , [ " opening " ] = 2 , [ " open " ] = 3 , [ " closing " ] = 4 } ,
book_animation_steps = { 0 , 640 , 680 , 700 , 740 } ,
2021-01-05 12:40:29 +01:00
book_animation_loop = { [ " open " ] = true , [ " close " ] = true } ,
2020-11-25 12:47:27 +01:00
book_animation_speed = 40 ,
2020-10-27 16:37:25 +01:00
roman_numerals = dofile ( modpath .. " /roman_numerals.lua " ) , -- https://exercism.io/tracks/lua/exercises/roman-numerals/solutions/73c2fb7521e347209312d115f872fa49
2020-11-01 13:44:05 +01:00
enchantments = { } ,
2020-12-22 10:42:22 +01:00
overlay = " ^[colorize:purple:50 " ,
--overlay = "^[invert:rgb^[multiply:#4df44d:50^[invert:rgb",
2020-12-17 13:29:21 +01:00
enchanting_lists = { " enchanting " , " enchanting_item " , " enchanting_lapis " } ,
2020-11-25 12:47:27 +01:00
bookshelf_positions = {
{ x = - 2 , y = 0 , z = - 2 } , { x = - 2 , y = 1 , z = - 2 } ,
{ x = - 1 , y = 0 , z = - 2 } , { x = - 1 , y = 1 , z = - 2 } ,
{ x = 0 , y = 0 , z = - 2 } , { x = 0 , y = 1 , z = - 2 } ,
{ x = 1 , y = 0 , z = - 2 } , { x = 1 , y = 1 , z = - 2 } ,
{ x = 2 , y = 0 , z = - 2 } , { x = 2 , y = 1 , z = - 2 } ,
{ x = - 2 , y = 0 , z = 2 } , { x = - 2 , y = 1 , z = 2 } ,
{ x = - 1 , y = 0 , z = 2 } , { x = - 1 , y = 1 , z = 2 } ,
{ x = 0 , y = 0 , z = 2 } , { x = 0 , y = 1 , z = 2 } ,
{ x = 1 , y = 0 , z = 2 } , { x = 1 , y = 1 , z = 2 } ,
{ x = 2 , y = 0 , z = 2 } , { x = 2 , y = 1 , z = 2 } ,
-- {x = -2, y = 0, z = -2}, {x = -2, y = 1, z = -2},
{ x = - 2 , y = 0 , z = - 1 } , { x = - 2 , y = 1 , z = - 1 } ,
{ x = - 2 , y = 0 , z = 0 } , { x = - 2 , y = 1 , z = 0 } ,
{ x = - 2 , y = 0 , z = 1 } , { x = - 2 , y = 1 , z = 1 } ,
2021-01-02 12:28:38 +01:00
-- {x = -2, y = 0, z = 2}, {x = -2, y = 1, z = 2},
-- {x = 2, y = 0, z = -2}, {x = 2, y = 1, z = -2},
2020-11-25 12:47:27 +01:00
{ x = 2 , y = 0 , z = - 1 } , { x = 2 , y = 1 , z = - 1 } ,
{ x = 2 , y = 0 , z = 0 } , { x = 2 , y = 1 , z = 0 } ,
{ x = 2 , y = 0 , z = 1 } , { x = 2 , y = 1 , z = 1 } ,
-- {x = 2, y = 0, z = 2}, {x = 2, y = 1, z = 2},
} ,
air_positions = {
{ x = - 1 , y = 0 , z = - 1 } , { x = - 1 , y = 1 , z = - 1 } ,
{ x = - 1 , y = 0 , z = - 1 } , { x = - 1 , y = 1 , z = - 1 } ,
{ x = 0 , y = 0 , z = - 1 } , { x = 0 , y = 1 , z = - 1 } ,
{ x = 1 , y = 0 , z = - 1 } , { x = 1 , y = 1 , z = - 1 } ,
{ x = 1 , y = 0 , z = - 1 } , { x = 1 , y = 1 , z = - 1 } ,
{ x = - 1 , y = 0 , z = 1 } , { x = - 1 , y = 1 , z = 1 } ,
{ x = - 1 , y = 0 , z = 1 } , { x = - 1 , y = 1 , z = 1 } ,
{ x = 0 , y = 0 , z = 1 } , { x = 0 , y = 1 , z = 1 } ,
{ x = 1 , y = 0 , z = 1 } , { x = 1 , y = 1 , z = 1 } ,
{ x = 1 , y = 0 , z = 1 } , { x = 1 , y = 1 , z = 1 } ,
-- {x = -1, y = 0, z = -1}, {x = -1, y = 1, z = -1},
{ x = - 1 , y = 0 , z = - 1 } , { x = - 1 , y = 1 , z = - 1 } ,
{ x = - 1 , y = 0 , z = 0 } , { x = - 1 , y = 1 , z = 0 } ,
{ x = - 1 , y = 0 , z = 1 } , { x = - 1 , y = 1 , z = 1 } ,
2021-01-02 12:28:38 +01:00
-- {x = -1, y = 0, z = 1}, {x = -1, y = 1, z = 1},
-- {x = 1, y = 0, z = -1}, {x = 1, y = 1, z = -1},
2020-11-25 12:47:27 +01:00
{ x = 1 , y = 0 , z = - 1 } , { x = 1 , y = 1 , z = - 1 } ,
{ x = 1 , y = 0 , z = 0 } , { x = 1 , y = 1 , z = 0 } ,
{ x = 1 , y = 0 , z = 1 } , { x = 1 , y = 1 , z = 1 } ,
-- {x = 1, y = 0, z = 1}, {x = 1, y = 1, z = 1},
} ,
2020-10-27 16:37:25 +01:00
}
2020-11-02 13:38:17 +01:00
dofile ( modpath .. " /engine.lua " )
2020-10-27 16:37:25 +01:00
dofile ( modpath .. " /enchantments.lua " )
2020-11-25 12:47:27 +01:00
minetest.register_chatcommand ( " enchant " , {
2020-12-14 14:08:55 +01:00
description = S ( " Enchant an item " ) ,
params = S ( " <player> <enchantment> [<level>] " ) ,
2020-11-25 12:47:27 +01:00
privs = { give = true } ,
func = function ( _ , param )
local sparam = param : split ( " " )
local target_name = sparam [ 1 ]
local enchantment = sparam [ 2 ]
local level_str = sparam [ 3 ]
local level = tonumber ( level_str or " 1 " )
if not target_name or not enchantment then
2020-12-14 14:08:55 +01:00
return false , S ( " Usage: /enchant <player> <enchantment> [<level>] " )
2020-11-25 12:47:27 +01:00
end
local target = minetest.get_player_by_name ( target_name )
if not target then
2020-12-14 14:08:55 +01:00
return false , S ( " Player '@1' cannot be found. " , target_name )
2020-11-25 12:47:27 +01:00
end
local itemstack = target : get_wielded_item ( )
local can_enchant , errorstring , extra_info = mcl_enchanting.can_enchant ( itemstack , enchantment , level )
if not can_enchant then
if errorstring == " enchantment invalid " then
2020-12-14 14:08:55 +01:00
return false , S ( " There is no such enchantment '@1'. " , enchantment )
2020-11-25 12:47:27 +01:00
elseif errorstring == " item missing " then
2020-12-14 14:08:55 +01:00
return false , S ( " The target doesn't hold an item. " )
2020-11-25 12:47:27 +01:00
elseif errorstring == " item not supported " then
2020-12-14 14:08:55 +01:00
return false , S ( " The selected enchantment can't be added to the target item. " )
2020-11-25 12:47:27 +01:00
elseif errorstring == " level invalid " then
2020-12-14 14:08:55 +01:00
return false , S ( " '@1' is not a valid number " , level_str )
2020-11-25 12:47:27 +01:00
elseif errorstring == " level too high " then
2020-12-14 14:08:55 +01:00
return false , S ( " The number you have entered (@1) is too big, it must be at most @2. " , level_str , extra_info )
2020-11-25 12:47:27 +01:00
elseif errorstring == " level too small " then
2020-12-14 14:08:55 +01:00
return false , S ( " The number you have entered (@1) is too small, it must be at least @2. " , level_str , extra_info )
2020-11-25 12:47:27 +01:00
elseif errorstring == " incompatible " then
2020-12-14 14:08:55 +01:00
return false , S ( " @1 can't be combined with @2. " , mcl_enchanting.get_enchantment_description ( enchantment , level ) , extra_info )
2020-11-25 12:47:27 +01:00
end
else
target : set_wielded_item ( mcl_enchanting.enchant ( itemstack , enchantment , level ) )
2020-12-14 14:08:55 +01:00
return true , S ( " Enchanting succeded. " )
2020-11-25 12:47:27 +01:00
end
end
} )
minetest.register_chatcommand ( " forceenchant " , {
2020-12-14 14:08:55 +01:00
description = S ( " Forcefully enchant an item " ) ,
params = S ( " <player> <enchantment> [<level>] " ) ,
2020-12-14 14:27:20 +01:00
privs = { give = true } ,
2020-11-25 12:47:27 +01:00
func = function ( _ , param )
local sparam = param : split ( " " )
local target_name = sparam [ 1 ]
local enchantment = sparam [ 2 ]
local level_str = sparam [ 3 ]
local level = tonumber ( level_str or " 1 " )
if not target_name or not enchantment then
2020-12-14 14:08:55 +01:00
return false , S ( " Usage: /forceenchant <player> <enchantment> [<level>] " )
2020-11-25 12:47:27 +01:00
end
local target = minetest.get_player_by_name ( target_name )
if not target then
2020-12-14 14:08:55 +01:00
return false , S ( " Player '@1' cannot be found. " , target_name )
2020-11-25 12:47:27 +01:00
end
local itemstack = target : get_wielded_item ( )
local can_enchant , errorstring , extra_info = mcl_enchanting.can_enchant ( itemstack , enchantment , level )
if errorstring == " enchantment invalid " then
2020-12-14 14:08:55 +01:00
return false , S ( " There is no such enchantment '@1'. " , enchantment )
2020-11-25 12:47:27 +01:00
elseif errorstring == " item missing " then
2020-12-14 14:08:55 +01:00
return false , S ( " The target doesn't hold an item. " )
2020-11-25 12:47:27 +01:00
elseif errorstring == " item not supported " and not mcl_enchanting.is_enchantable ( itemstack : get_name ( ) ) then
2020-12-14 14:08:55 +01:00
return false , S ( " The target item is not enchantable. " )
2020-11-25 12:47:27 +01:00
elseif errorstring == " level invalid " then
2020-12-14 14:08:55 +01:00
return false , S ( " '@1' is not a valid number. " , level_str )
2020-11-25 12:47:27 +01:00
else
target : set_wielded_item ( mcl_enchanting.enchant ( itemstack , enchantment , level ) )
2020-12-14 14:08:55 +01:00
return true , S ( " Enchanting succeded. " )
2020-11-25 12:47:27 +01:00
end
end
} )
minetest.register_craftitem ( " mcl_enchanting:book_enchanted " , {
2020-12-14 14:08:55 +01:00
description = S ( " Enchanted Book " ) ,
2020-11-25 12:47:27 +01:00
inventory_image = " mcl_enchanting_book_enchanted.png " .. mcl_enchanting.overlay ,
groups = { enchanted = 1 , not_in_creative_inventory = 1 , enchantability = 1 } ,
_mcl_enchanting_enchanted_tool = " mcl_enchanting:book_enchanted " ,
stack_max = 1 ,
} )
2020-12-18 15:57:52 +01:00
minetest.register_alias ( " mcl_books:book_enchanted " , " mcl_enchanting:book_enchanted " )
2020-12-14 19:15:40 +01:00
local spawn_book_entity = function ( pos , respawn )
if respawn then
-- Check if we already have a book
local objs = minetest.get_objects_inside_radius ( pos , 1 )
for o = 1 , # objs do
local obj = objs [ o ]
local lua = obj : get_luaentity ( )
if lua and lua.name == " mcl_enchanting:book " then
if lua._table_pos and vector.equals ( pos , lua._table_pos ) then
return
end
end
end
end
2020-12-14 19:08:57 +01:00
local obj = minetest.add_entity ( vector.add ( pos , mcl_enchanting.book_offset ) , " mcl_enchanting:book " )
if obj then
local lua = obj : get_luaentity ( )
if lua then
lua._table_pos = table.copy ( pos )
end
end
end
2020-11-25 12:47:27 +01:00
minetest.register_entity ( " mcl_enchanting:book " , {
initial_properties = {
visual = " mesh " ,
mesh = " mcl_enchanting_book.b3d " ,
visual_size = { x = 12.5 , y = 12.5 } ,
collisionbox = { 0 , 0 , 0 } ,
2020-12-14 18:53:34 +01:00
pointable = false ,
2020-11-25 12:47:27 +01:00
physical = false ,
textures = { " mcl_enchanting_book_entity.png " } ,
2020-12-14 19:08:57 +01:00
static_save = false ,
2020-11-25 12:47:27 +01:00
} ,
2020-12-14 18:24:24 +01:00
_player_near = false ,
_table_pos = nil ,
on_activate = function ( self , staticdata )
2020-11-25 12:47:27 +01:00
self.object : set_armor_groups ( { immortal = 1 } )
mcl_enchanting.set_book_animation ( self , " close " )
end ,
on_step = function ( self , dtime )
2020-12-14 18:24:24 +01:00
local old_player_near = self._player_near
2020-11-25 12:47:27 +01:00
local player_near = false
local player
for _ , obj in ipairs ( minetest.get_objects_inside_radius ( vector.subtract ( self.object : get_pos ( ) , mcl_enchanting.book_offset ) , 2.5 ) ) do
if obj : is_player ( ) then
player_near = true
player = obj
end
end
if player_near and not old_player_near then
mcl_enchanting.set_book_animation ( self , " opening " )
mcl_enchanting.schedule_book_animation ( self , " open " )
elseif old_player_near and not player_near then
mcl_enchanting.set_book_animation ( self , " closing " )
mcl_enchanting.schedule_book_animation ( self , " close " )
end
if player then
mcl_enchanting.look_at ( self , player : get_pos ( ) )
end
2020-12-14 18:24:24 +01:00
self._player_near = player_near
2020-11-25 12:47:27 +01:00
mcl_enchanting.check_animation_schedule ( self , dtime )
end ,
} )
2020-12-14 14:27:20 +01:00
local rotate
if minetest.get_modpath ( " screwdriver " ) then
rotate = screwdriver.rotate_simple
end
2020-11-25 12:47:27 +01:00
minetest.register_node ( " mcl_enchanting:table " , {
2020-12-14 14:08:55 +01:00
description = S ( " Enchanting Table " ) ,
2021-01-27 08:41:23 +01:00
_tt_help = S ( " Spend experience, and lapis to enchant various items. " ) ,
_doc_items_longdesc = S ( " Enchanting Tables will let you enchant armors, tools, weapons, and books with various abilities. But, at the cost of some experience, and lapis lazuli. " ) ,
_doc_items_usagehelp =
S ( " Rightclick the Enchanting Table to open the enchanting menu. " ) .. " \n " ..
S ( " Place a tool, armor, weapon or book into the top left slot, and then place 1-3 Lapis Lazuli in the slot to the right. " ) .. " \n " .. " \n " ..
S ( " After placing your items in the slots, the enchanting options will be shown. Hover over the options to read what is available to you. " ) .. " \n " ..
S ( " These options are randomized, and dependent on experience level; but the enchantment strength can be increased. " ) .. " \n " .. " \n " ..
S ( " To increase the enchantment strength, place bookshelves around the enchanting table. However, you will need to keep 1 air node between the table, & the bookshelves to empower the enchanting table. " ) .. " \n " .. " \n " ..
S ( " After finally selecting your enchantment; left-click on the selection, and you will see both the lapis lazuli and your experience levels consumed. And, an enchanted item left in its place. " ) ,
_doc_items_hidden = false ,
2020-11-25 12:47:27 +01:00
drawtype = " nodebox " ,
tiles = { " mcl_enchanting_table_top.png " , " mcl_enchanting_table_bottom.png " , " mcl_enchanting_table_side.png " , " mcl_enchanting_table_side.png " , " mcl_enchanting_table_side.png " , " mcl_enchanting_table_side.png " } ,
node_box = {
type = " fixed " ,
fixed = { - 0.5 , - 0.5 , - 0.5 , 0.5 , 0.25 , 0.5 } ,
} ,
sounds = mcl_sounds.node_sound_stone_defaults ( ) ,
2020-12-14 14:27:20 +01:00
groups = { pickaxey = 2 , deco_block = 1 } ,
on_rotate = rotate ,
2020-11-25 12:47:27 +01:00
on_rightclick = function ( pos , node , clicker , itemstack , pointed_thing )
local player_meta = clicker : get_meta ( )
local table_meta = minetest.get_meta ( pos )
local num_bookshelves = table_meta : get_int ( " mcl_enchanting:num_bookshelves " )
local table_name = table_meta : get_string ( " name " )
if table_name == " " then
2020-12-14 14:08:55 +01:00
table_name = S ( " Enchant " )
2020-11-25 12:47:27 +01:00
end
2021-01-02 12:21:35 +01:00
local bookshelves = mcl_enchanting.get_bookshelves ( pos )
player_meta : set_int ( " mcl_enchanting:num_bookshelves " , math.min ( 15 , # bookshelves ) )
2020-11-25 12:47:27 +01:00
player_meta : set_string ( " mcl_enchanting:table_name " , table_name )
mcl_enchanting.show_enchanting_formspec ( clicker )
2020-12-14 19:15:40 +01:00
-- Respawn book entity just in case it got lost
spawn_book_entity ( pos , true )
2020-11-25 12:47:27 +01:00
end ,
on_construct = function ( pos )
2020-12-14 19:08:57 +01:00
spawn_book_entity ( pos )
2020-11-25 12:47:27 +01:00
end ,
2020-12-14 18:53:34 +01:00
after_dig_node = function ( pos , oldnode , oldmetadata , digger )
local dname = ( digger and digger : get_player_name ( ) ) or " "
if minetest.is_creative_enabled ( dname ) then
return
end
2020-11-25 12:47:27 +01:00
local itemstack = ItemStack ( " mcl_enchanting:table " )
local meta = minetest.get_meta ( pos )
local itemmeta = itemstack : get_meta ( )
itemmeta : set_string ( " name " , meta : get_string ( " name " ) )
itemmeta : set_string ( " description " , meta : get_string ( " description " ) )
minetest.add_item ( pos , itemstack )
end ,
after_place_node = function ( pos , placer , itemstack , pointed_thing )
local meta = minetest.get_meta ( pos )
local itemmeta = itemstack : get_meta ( )
meta : set_string ( " name " , itemmeta : get_string ( " name " ) )
meta : set_string ( " description " , itemmeta : get_string ( " description " ) )
end ,
2020-12-14 18:24:24 +01:00
after_destruct = function ( pos )
local objs = minetest.get_objects_inside_radius ( pos , 1 )
for o = 1 , # objs do
local obj = objs [ o ]
local lua = obj : get_luaentity ( )
if lua and lua.name == " mcl_enchanting:book " then
if lua._table_pos and vector.equals ( pos , lua._table_pos ) then
obj : remove ( )
end
end
end
end ,
2020-11-25 12:47:27 +01:00
drop = " " ,
_mcl_blast_resistance = 1200 ,
_mcl_hardness = 5 ,
2021-01-05 12:40:29 +01:00
} )
2020-11-25 12:47:27 +01:00
minetest.register_craft ( {
output = " mcl_enchanting:table " ,
recipe = {
{ " " , " mcl_books:book " , " " } ,
{ " mcl_core:diamond " , " mcl_core:obsidian " , " mcl_core:diamond " } ,
{ " mcl_core:obsidian " , " mcl_core:obsidian " , " mcl_core:obsidian " }
}
} )
minetest.register_abm ( {
2020-12-14 14:27:20 +01:00
label = " Enchanting table bookshelf particles " ,
2020-11-25 12:47:27 +01:00
interval = 1 ,
chance = 1 ,
nodenames = " mcl_enchanting:table " ,
action = function ( pos )
2021-01-04 18:58:53 +01:00
local playernames = { }
for _ , obj in ipairs ( minetest.get_objects_inside_radius ( pos , 15 ) ) do
if obj : is_player ( ) then
table.insert ( playernames , obj : get_player_name ( ) )
end
end
if # playernames < 1 then
return
end
2020-11-25 12:47:27 +01:00
local absolute , relative = mcl_enchanting.get_bookshelves ( pos )
for i , ap in ipairs ( absolute ) do
2021-01-04 18:58:53 +01:00
if math.random ( 5 ) == 1 then
2020-11-25 12:47:27 +01:00
local rp = relative [ i ]
2021-01-04 18:58:53 +01:00
local t = math.random ( ) + 1 --time
local d = { x = rp.x , y = rp.y - 0.7 , z = rp.z } --distance
local v = { x = - math.random ( ) * d.x , y = math.random ( ) , z = - math.random ( ) * d.z } --velocity
local a = { x = 2 * ( - v.x * t - d.x ) / t / t , y = 2 * ( - v.y * t - d.y ) / t / t , z = 2 * ( - v.z * t - d.z ) / t / t } --acceleration
local s = math.random ( ) + 0.9 --size
t = t - 0.1 --slightly decrease time to avoid texture overlappings
local tx = " mcl_enchanting_glyph_ " .. math.random ( 18 ) .. " .png "
for _ , name in pairs ( playernames ) do
minetest.add_particle ( {
pos = ap ,
velocity = v ,
acceleration = a ,
expirationtime = t ,
size = s ,
texture = tx ,
collisiondetection = false ,
playername = name
} )
end
2020-11-25 12:47:27 +01:00
end
end
end
2021-01-05 12:40:29 +01:00
} )
2020-11-01 13:44:05 +01:00
2020-12-14 19:08:57 +01:00
minetest.register_lbm ( {
label = " (Re-)spawn book entity above enchanting table " ,
name = " mcl_enchanting:spawn_book_entity " ,
nodenames = { " mcl_enchanting:table " } ,
run_at_every_load = true ,
action = function ( pos )
spawn_book_entity ( pos )
end ,
} )
2020-11-01 13:44:05 +01:00
minetest.register_on_mods_loaded ( mcl_enchanting.initialize )
2020-11-25 12:47:27 +01:00
minetest.register_on_joinplayer ( mcl_enchanting.initialize_player )
minetest.register_on_player_receive_fields ( mcl_enchanting.handle_formspec_fields )
2020-12-17 13:29:21 +01:00
minetest.register_allow_player_inventory_action ( mcl_enchanting.allow_inventory_action )
minetest.register_on_player_inventory_action ( mcl_enchanting.on_inventory_action )
2021-01-05 12:40:29 +01:00
table.insert ( tt.registered_snippets , 1 , m cl_enchanting.enchantments_snippet )