2024-06-12 19:41:16 +02:00
local modname = minetest.get_current_modname ( )
local modpath = minetest.get_modpath ( modname )
local S = minetest.get_translator ( modname )
local math = math
local vector = vector
2024-06-13 16:37:19 +02:00
redstone_enchanting = {
2024-06-12 19:41:16 +02:00
book_offset = vector.new ( 0 , 0.75 , 0 ) ,
book_animations = { [ " close " ] = 1 , [ " opening " ] = 2 , [ " open " ] = 3 , [ " closing " ] = 4 } ,
book_animation_steps = { 0 , 640 , 680 , 700 , 740 } ,
book_animation_loop = { [ " open " ] = true , [ " close " ] = true } ,
book_animation_speed = 40 ,
enchantments = { } ,
overlay = " ^[colorize:purple:50 " ,
--overlay = "^[invert:rgb^[multiply:#4df44d:50^[invert:rgb",
2024-06-13 16:37:19 +02:00
enchanting_lists = { " enchanting " , " enchanting_item " , " enchanting_redstone " } ,
2024-06-12 19:41:16 +02: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 } ,
-- {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 } ,
-- {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 } ,
-- {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 } ,
-- {x = 1, y = 0, z = 1}, {x = 1, y = 1, z = 1},
} ,
}
dofile ( modpath .. " /engine.lua " )
dofile ( modpath .. " /groupcaps.lua " )
dofile ( modpath .. " /enchantments.lua " )
minetest.register_chatcommand ( " enchant " , {
description = S ( " Enchant an item " ) ,
params = S ( " <player> <enchantment> [<level>] " ) ,
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
return false , S ( " Usage: /enchant <player> <enchantment> [<level>] " )
end
local target = minetest.get_player_by_name ( target_name )
if not target then
return false , S ( " Player '@1' cannot be found. " , target_name )
end
local itemstack = target : get_wielded_item ( )
2024-06-13 16:37:19 +02:00
local can_enchant , errorstring , extra_info = redstone_enchanting.can_enchant ( itemstack , enchantment , level )
2024-06-12 19:41:16 +02:00
if not can_enchant then
if errorstring == " enchantment invalid " then
return false , S ( " There is no such enchantment '@1'. " , enchantment )
elseif errorstring == " item missing " then
return false , S ( " The target doesn't hold an item. " )
elseif errorstring == " item not supported " then
return false , S ( " The selected enchantment can't be added to the target item. " )
elseif errorstring == " level invalid " then
return false , S ( " '@1' is not a valid number " , level_str )
elseif errorstring == " level too high " then
return false , S ( " The number you have entered (@1) is too big, it must be at most @2. " , level_str , extra_info )
elseif errorstring == " level too small " then
return false , S ( " The number you have entered (@1) is too small, it must be at least @2. " , level_str , extra_info )
elseif errorstring == " incompatible " then
2024-06-13 16:37:19 +02:00
return false , S ( " @1 can't be combined with @2. " , redstone_enchanting.get_enchantment_description ( enchantment , level ) , extra_info )
2024-06-12 19:41:16 +02:00
end
else
2024-06-13 16:37:19 +02:00
target : set_wielded_item ( redstone_enchanting.enchant ( itemstack , enchantment , level ) )
2024-06-12 19:41:16 +02:00
return true , S ( " Enchanting succeded. " )
end
end
} )
minetest.register_chatcommand ( " forceenchant " , {
description = S ( " Forcefully enchant an item " ) ,
params = S ( " <player> <enchantment> [<level>] " ) ,
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
return false , S ( " Usage: /forceenchant <player> <enchantment> [<level>] " )
end
local target = minetest.get_player_by_name ( target_name )
if not target then
return false , S ( " Player '@1' cannot be found. " , target_name )
end
local itemstack = target : get_wielded_item ( )
2024-06-13 16:37:19 +02:00
local _ , errorstring = redstone_enchanting.can_enchant ( itemstack , enchantment , level )
2024-06-12 19:41:16 +02:00
if errorstring == " enchantment invalid " then
return false , S ( " There is no such enchantment '@1'. " , enchantment )
elseif errorstring == " item missing " then
return false , S ( " The target doesn't hold an item. " )
2024-06-13 16:37:19 +02:00
elseif errorstring == " item not supported " and not redstone_enchanting.is_enchantable ( itemstack : get_name ( ) ) then
2024-06-12 19:41:16 +02:00
return false , S ( " The target item is not enchantable. " )
elseif errorstring == " level invalid " then
return false , S ( " '@1' is not a valid number. " , level_str )
else
2024-06-13 16:37:19 +02:00
target : set_wielded_item ( redstone_enchanting.enchant ( itemstack , enchantment , level ) )
2024-06-12 19:41:16 +02:00
return true , S ( " Enchanting succeded. " )
end
end
} )
2024-06-13 16:37:19 +02:00
minetest.register_craftitem ( " redstone_enchanting:book_enchanted " , {
2024-06-12 19:41:16 +02:00
description = S ( " Enchanted Book " ) ,
2024-06-13 16:37:19 +02:00
inventory_image = " redstone_enchanting_book_enchanted.png " .. redstone_enchanting.overlay ,
2024-06-12 19:41:16 +02:00
groups = { enchanted = 1 , not_in_creative_inventory = 1 , enchantability = 1 } ,
2024-06-13 16:37:19 +02:00
_redstone_enchanting_enchanted_tool = " redstone_enchanting:book_enchanted " ,
2024-06-12 19:41:16 +02:00
stack_max = 1 ,
} )
2024-06-13 16:37:19 +02:00
minetest.register_alias ( " mcl_books:book_enchanted " , " redstone_enchanting:book_enchanted " )
2024-06-12 19:41:16 +02:00
local function spawn_book_entity ( 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 ( )
2024-06-13 16:37:19 +02:00
if lua and lua.name == " redstone_enchanting:book " then
2024-06-12 19:41:16 +02:00
if lua._table_pos and vector.equals ( pos , lua._table_pos ) then
return
end
end
end
end
2024-06-13 16:37:19 +02:00
local obj = minetest.add_entity ( vector.add ( pos , redstone_enchanting.book_offset ) , " redstone_enchanting:book " )
2024-06-12 19:41:16 +02:00
if obj then
local lua = obj : get_luaentity ( )
if lua then
lua._table_pos = table.copy ( pos )
end
end
end
2024-06-13 16:37:19 +02:00
minetest.register_entity ( " redstone_enchanting:book " , {
2024-06-12 19:41:16 +02:00
initial_properties = {
visual = " mesh " ,
2024-06-13 16:37:19 +02:00
mesh = " redstone_enchanting_book.b3d " ,
2024-06-12 19:41:16 +02:00
visual_size = { x = 12.5 , y = 12.5 } ,
collisionbox = { 0 , 0 , 0 } ,
pointable = false ,
physical = false ,
2024-06-13 16:37:19 +02:00
textures = { " redstone_enchanting_book_entity.png " , " redstone_enchanting_book_entity.png " , " redstone_enchanting_book_entity.png " , " redstone_enchanting_book_entity.png " , " redstone_enchanting_book_entity.png " } ,
2024-06-12 19:41:16 +02:00
static_save = false ,
} ,
_player_near = false ,
_table_pos = nil ,
on_activate = function ( self , staticdata )
self.object : set_armor_groups ( { immortal = 1 } )
2024-06-13 16:37:19 +02:00
redstone_enchanting.set_book_animation ( self , " close " )
2024-06-12 19:41:16 +02:00
end ,
on_step = function ( self , dtime )
local old_player_near = self._player_near
local player_near = false
local player
2024-06-13 16:37:19 +02:00
for _ , obj in pairs ( minetest.get_objects_inside_radius ( vector.subtract ( self.object : get_pos ( ) , redstone_enchanting.book_offset ) , 2.5 ) ) do
2024-06-12 19:41:16 +02:00
if obj : is_player ( ) then
player_near = true
player = obj
end
end
if player_near and not old_player_near then
2024-06-13 16:37:19 +02:00
redstone_enchanting.set_book_animation ( self , " opening " )
redstone_enchanting.schedule_book_animation ( self , " open " )
2024-06-12 19:41:16 +02:00
elseif old_player_near and not player_near then
2024-06-13 16:37:19 +02:00
redstone_enchanting.set_book_animation ( self , " closing " )
redstone_enchanting.schedule_book_animation ( self , " close " )
2024-06-12 19:41:16 +02:00
end
if player then
2024-06-13 16:37:19 +02:00
redstone_enchanting.look_at ( self , player : get_pos ( ) )
2024-06-12 19:41:16 +02:00
end
self._player_near = player_near
2024-06-13 16:37:19 +02:00
redstone_enchanting.check_animation_schedule ( self , dtime )
2024-06-12 19:41:16 +02:00
end ,
} )
local rotate
if minetest.get_modpath ( " screwdriver " ) then
rotate = screwdriver.rotate_simple
end
2024-06-13 16:37:19 +02:00
minetest.register_node ( " redstone_enchanting:table " , {
2024-06-12 19:41:16 +02:00
description = S ( " Enchanting Table " ) ,
2024-06-13 16:37:19 +02:00
_tt_help = S ( " Spend experience, and redstone 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 redstone . " ) ,
2024-06-12 19:41:16 +02:00
_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 " ..
2024-06-13 16:37:19 +02:00
S ( " After finally selecting your enchantment; left-click on the selection, and you will see both the redstone and your experience levels consumed. And, an enchanted item left in its place. " ) ,
2024-06-12 19:41:16 +02:00
_doc_items_hidden = false ,
drawtype = " nodebox " ,
2024-06-13 16:37:19 +02:00
tiles = { " redstone_enchanting_table_top.png " , " redstone_enchanting_table_bottom.png " , " redstone_enchanting_table_side.png " , " redstone_enchanting_table_side.png " , " redstone_enchanting_table_side.png " , " redstone_enchanting_table_side.png " } ,
2024-06-12 19:41:16 +02:00
use_texture_alpha = minetest.features . use_texture_alpha_string_modes and " opaque " or false ,
node_box = {
type = " fixed " ,
fixed = { - 0.5 , - 0.5 , - 0.5 , 0.5 , 0.25 , 0.5 } ,
} ,
sounds = mcl_sounds.node_sound_stone_defaults ( ) ,
groups = { pickaxey = 2 , deco_block = 1 } ,
on_rotate = rotate ,
on_rightclick = function ( pos , node , clicker , itemstack , pointed_thing )
local player_meta = clicker : get_meta ( )
--local table_meta = minetest.get_meta(pos)
2024-06-13 16:37:19 +02:00
--local num_bookshelves = table_meta:get_int("redstone_enchanting:num_bookshelves")
2024-06-12 19:41:16 +02:00
local table_name = minetest.get_meta ( pos ) : get_string ( " name " )
if table_name == " " then
table_name = S ( " Enchant " )
end
2024-06-13 16:37:19 +02:00
local bookshelves = redstone_enchanting.get_bookshelves ( pos )
player_meta : set_int ( " redstone_enchanting:num_bookshelves " , math.min ( 15 , # bookshelves ) )
player_meta : set_string ( " redstone_enchanting:table_name " , table_name )
redstone_enchanting.show_enchanting_formspec ( clicker )
2024-06-12 19:41:16 +02:00
-- Respawn book entity just in case it got lost
spawn_book_entity ( pos , true )
end ,
on_construct = function ( pos )
spawn_book_entity ( pos )
end ,
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
2024-06-13 16:37:19 +02:00
local itemstack = ItemStack ( " redstone_enchanting:table " )
2024-06-12 19:41:16 +02:00
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 ,
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 ( )
2024-06-13 16:37:19 +02:00
if lua and lua.name == " redstone_enchanting:book " then
2024-06-12 19:41:16 +02:00
if lua._table_pos and vector.equals ( pos , lua._table_pos ) then
obj : remove ( )
end
end
end
end ,
drop = " " ,
_mcl_blast_resistance = 1200 ,
_mcl_hardness = 5 ,
} )
minetest.register_craft ( {
2024-06-13 16:37:19 +02:00
output = " redstone_enchanting:table " ,
2024-06-12 19:41:16 +02:00
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 ( {
label = " Enchanting table bookshelf particles " ,
interval = 1 ,
chance = 1 ,
2024-06-13 16:37:19 +02:00
nodenames = " redstone_enchanting:table " ,
2024-06-12 19:41:16 +02:00
action = function ( pos )
local playernames = { }
for _ , obj in pairs ( 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
2024-06-13 16:37:19 +02:00
local absolute , relative = redstone_enchanting.get_bookshelves ( pos )
2024-06-12 19:41:16 +02:00
for i , ap in ipairs ( absolute ) do
if math.random ( 5 ) == 1 then
local rp = relative [ i ]
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
2024-06-13 16:37:19 +02:00
local tx = " redstone_enchanting_glyph_ " .. math.random ( 18 ) .. " .png "
2024-06-12 19:41:16 +02:00
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
end
end
end
} )
minetest.register_lbm ( {
label = " (Re-)spawn book entity above enchanting table " ,
2024-06-13 16:37:19 +02:00
name = " redstone_enchanting:spawn_book_entity " ,
nodenames = { " redstone_enchanting:table " } ,
2024-06-12 19:41:16 +02:00
run_at_every_load = true ,
action = function ( pos )
spawn_book_entity ( pos , true )
end ,
} )
2024-06-13 16:37:19 +02:00
minetest.register_on_mods_loaded ( redstone_enchanting.initialize )
minetest.register_on_joinplayer ( redstone_enchanting.initialize_player )
minetest.register_on_player_receive_fields ( redstone_enchanting.handle_formspec_fields )
minetest.register_allow_player_inventory_action ( redstone_enchanting.allow_inventory_action )
minetest.register_on_player_inventory_action ( redstone_enchanting.on_inventory_action )
tt.register_priority_snippet ( redstone_enchanting.enchantments_snippet )