2022-08-18 20:45:30 +02:00
-- Code based from mcl_anvils
2023-08-31 17:59:46 +02:00
mcl_grindstone = { }
2022-06-20 21:46:59 +02:00
local S = minetest.get_translator ( minetest.get_current_modname ( ) )
2022-09-10 22:34:31 +02:00
local F = minetest.formspec_escape
local C = minetest.colorize
2022-06-20 21:46:59 +02:00
2022-08-14 17:49:35 +02:00
local MAX_WEAR = 65535
2022-09-10 22:34:31 +02:00
local grindstone_formspec = table.concat ( {
" formspec_version[6] " ,
" size[11.75,10.425] " ,
" label[0.375,0.375; " .. F ( C ( mcl_formspec.label_color , S ( " Repair & Disenchant " ) ) ) .. " ] " ,
mcl_formspec.get_itemslot_bg_v4 ( 2.875 , 1.25 , 1 , 1 ) ,
" list[context;input;2.875,1.25;1,1;] " ,
mcl_formspec.get_itemslot_bg_v4 ( 2.875 , 2.625 , 1 , 1 ) ,
" list[context;input;2.875,2.625;1,1;1] " ,
" image[2.375,1;2,2.875;grindstone_gui_9.png;2] " ,
" image[1.875,1.5;0.5,2.875;grindstone_gui_9.png;2] " ,
" image[4.375,1.5;0.5,2.875;grindstone_gui_9.png;2] " ,
" image[5.5,1.95;1.5,1;gui_crafting_arrow.png] " ,
mcl_formspec.get_itemslot_bg_v4 ( 7.875 , 1.9375 , 1 , 1 ) ,
" list[context;output;7.875,1.9375;1,1;] " ,
" label[0.375,4.7; " .. F ( C ( mcl_formspec.label_color , S ( " Inventory " ) ) ) .. " ] " ,
mcl_formspec.get_itemslot_bg_v4 ( 0.375 , 5.1 , 9 , 3 ) ,
" list[current_player;main;0.375,5.1;9,3;9] " ,
mcl_formspec.get_itemslot_bg_v4 ( 0.375 , 9.05 , 9 , 1 ) ,
" list[current_player;main;0.375,9.05;9,1;] " ,
" listring[context;output] " ,
" listring[current_player;main] " ,
" listring[context;input] " ,
" listring[current_player;main] " ,
} )
2022-08-14 17:49:35 +02:00
2022-08-17 22:47:00 +02:00
-- Creates a new item with the wear of the items and custom name
2022-08-16 23:06:49 +02:00
local function create_new_item ( name_item , meta , wear )
local new_item = ItemStack ( name_item )
2022-08-18 21:25:43 +02:00
if wear ~= nil then
2022-09-10 22:34:31 +02:00
new_item : set_wear ( wear )
2022-08-18 21:25:43 +02:00
end
2022-08-16 23:06:49 +02:00
local new_meta = new_item : get_meta ( )
new_meta : set_string ( " name " , meta : get_string ( " name " ) )
tt.reload_itemstack_description ( new_item )
return new_item
end
2022-08-17 22:47:00 +02:00
-- If an item has an enchanment then remove "_enchanted" from the name
2023-08-31 17:59:46 +02:00
function mcl_grindstone . remove_enchant_name ( stack )
2022-08-16 23:06:49 +02:00
if mcl_enchanting.is_enchanted ( stack : get_name ( ) ) then
local name = stack : get_name ( )
return name.sub ( name , 1 , - 11 )
else
return stack : get_name ( )
end
end
2022-08-17 22:47:00 +02:00
-- If an input has a curse transfer it to the new item
2022-08-16 23:06:49 +02:00
local function transfer_curse ( old_itemstack , new_itemstack )
local enchants = mcl_enchanting.get_enchantments ( old_itemstack )
for enchant , level in pairs ( enchants ) do
if mcl_enchanting.enchantments [ enchant ] . curse == true then
new_itemstack = mcl_enchanting.enchant ( new_itemstack , enchant , level )
end
end
return new_itemstack
end
2022-08-17 22:47:00 +02:00
-- Depending on an enchantment level and isn't a curse multiply xp given
local function calculate_xp ( stack )
local xp = 0
local enchants = mcl_enchanting.get_enchantments ( stack )
for enchant , level in pairs ( enchants ) do
if level > 0 and mcl_enchanting.enchantments [ enchant ] . curse == false then
2022-08-18 21:25:43 +02:00
-- Add a bit of uniform randomisation
2022-08-17 22:47:00 +02:00
xp = xp + math.random ( 7 , 13 ) * level
end
end
return xp
end
-- Helper function to make sure update_grindstone_slots NEVER overstacks the output slot
2022-08-14 17:49:35 +02:00
local function fix_stack_size ( stack )
if not stack or stack == " " then return " " end
local count = stack : get_count ( )
local max_count = stack : get_stack_max ( )
if count > max_count then
stack : set_count ( max_count )
count = max_count
end
return count
end
2022-08-17 22:47:00 +02:00
-- Update the inventory slots of an grindstone node.
-- meta: Metadata of grindstone node
2022-08-14 17:49:35 +02:00
local function update_grindstone_slots ( meta )
local inv = meta : get_inventory ( )
local input1 = inv : get_stack ( " input " , 1 )
local input2 = inv : get_stack ( " input " , 2 )
2022-08-16 23:06:49 +02:00
local meta = input1 : get_meta ( )
2022-08-14 17:49:35 +02:00
local new_output
2022-08-17 22:47:00 +02:00
-- Both input slots are occupied
2022-08-14 17:49:35 +02:00
if ( not input1 : is_empty ( ) and not input2 : is_empty ( ) ) then
local def1 = input1 : get_definition ( )
local def2 = input2 : get_definition ( )
2022-08-17 22:47:00 +02:00
-- Remove enchant name if they have one
2023-08-31 17:59:46 +02:00
local name1 = mcl_grindstone.remove_enchant_name ( input1 )
local name2 = mcl_grindstone.remove_enchant_name ( input2 )
2022-08-14 17:49:35 +02:00
2022-08-17 22:47:00 +02:00
-- Calculate repair
2022-08-14 17:49:35 +02:00
local function calculate_repair ( dur1 , dur2 )
2022-08-17 22:47:00 +02:00
-- Grindstone gives a 5% bonus to durability
2022-08-14 17:49:35 +02:00
local new_durability = ( MAX_WEAR - dur1 ) + ( MAX_WEAR - dur2 ) * 1.05
return math.max ( 0 , math.min ( MAX_WEAR , MAX_WEAR - new_durability ) )
end
2022-08-17 22:47:00 +02:00
-- Check if both are tools and have the same tool type
2022-08-14 17:49:35 +02:00
if def1.type == " tool " and def2.type == " tool " and name1 == name2 then
local new_wear = calculate_repair ( input1 : get_wear ( ) , input2 : get_wear ( ) )
2022-08-16 23:06:49 +02:00
local new_item = create_new_item ( name1 , meta , new_wear )
2022-08-17 22:47:00 +02:00
-- Transfer curses if both items have any
new_output = transfer_curse ( input1 , new_item )
new_output = transfer_curse ( input2 , new_output )
2022-08-14 17:49:35 +02:00
else
new_output = " "
end
2022-09-10 22:34:31 +02:00
-- Check if at least one input has an item
-- Check if the item is's an enchanted book or tool
2022-08-16 23:06:49 +02:00
elseif ( not input1 : is_empty ( ) and input2 : is_empty ( ) ) or ( input1 : is_empty ( ) and not input2 : is_empty ( ) ) then
if input2 : is_empty ( ) then
local def1 = input1 : get_definition ( )
local meta = input1 : get_meta ( )
if def1.type == " tool " and mcl_enchanting.is_enchanted ( input1 : get_name ( ) ) then
2023-08-31 17:59:46 +02:00
local name = mcl_grindstone.remove_enchant_name ( input1 )
2022-08-16 23:06:49 +02:00
local wear = input1 : get_wear ( )
local new_item = create_new_item ( name , meta , wear )
new_output = transfer_curse ( input1 , new_item )
2022-08-18 20:45:30 +02:00
elseif input1 : get_name ( ) == " mcl_enchanting:book_enchanted " then
2022-08-18 21:25:43 +02:00
new_item = create_new_item ( " mcl_books:book " , meta , nil )
2022-08-18 20:45:30 +02:00
new_output = transfer_curse ( input1 , new_item )
2022-08-16 23:06:49 +02:00
else
new_output = " "
end
else
local def2 = input2 : get_definition ( )
local meta = input2 : get_meta ( )
if def2.type == " tool " and mcl_enchanting.is_enchanted ( input2 : get_name ( ) ) then
2023-08-31 17:59:46 +02:00
local name = mcl_grindstone.remove_enchant_name ( input2 )
2022-08-16 23:06:49 +02:00
local wear = input2 : get_wear ( )
local new_item = create_new_item ( name , meta , wear )
new_output = transfer_curse ( input2 , new_item )
2022-08-18 20:45:30 +02:00
elseif input2 : get_name ( ) == " mcl_enchanting:book_enchanted " then
2022-08-18 21:25:43 +02:00
new_item = create_new_item ( " mcl_books:book " , meta , nil )
2022-08-18 20:45:30 +02:00
new_output = transfer_curse ( input2 , new_item )
2022-08-16 23:06:49 +02:00
else
new_output = " "
end
end
2022-08-14 17:49:35 +02:00
else
new_output = " "
end
-- Set the new output slot
if new_output then
fix_stack_size ( new_output )
inv : set_stack ( " output " , 1 , new_output )
end
end
2022-08-18 20:45:30 +02:00
-- Drop any items inside the grindstone if destroyed
local function drop_grindstone_items ( pos , meta )
local inv = meta : get_inventory ( )
2022-09-10 22:34:31 +02:00
for i = 1 , inv : get_size ( " input " ) do
2022-08-18 20:45:30 +02:00
local stack = inv : get_stack ( " input " , i )
if not stack : is_empty ( ) then
2022-09-10 22:34:31 +02:00
local p = { x = pos.x + math.random ( 0 , 10 ) / 10 - 0.5 , y = pos.y , z = pos.z + math.random ( 0 , 10 ) / 10 - 0.5 }
2022-08-18 20:45:30 +02:00
minetest.add_item ( p , stack )
end
end
end
2022-08-28 15:02:02 +02:00
local node_box = {
type = " fixed " ,
-- created with nodebox editor
fixed = {
2022-09-10 22:34:31 +02:00
{ - 0.25 , - 0.25 , - 0.375 , 0.25 , 0.5 , 0.375 } ,
{ - 0.375 , - 0.0625 , - 0.1875 , - 0.25 , 0.3125 , 0.1875 } ,
{ 0.25 , - 0.0625 , - 0.1875 , 0.375 , 0.3125 , 0.1875 } ,
{ 0.25 , - 0.5 , - 0.125 , 0.375 , - 0.0625 , 0.125 } ,
{ - 0.375 , - 0.5 , - 0.125 , - 0.25 , - 0.0625 , 0.125 } ,
2022-08-28 15:02:02 +02:00
}
}
2022-06-20 21:46:59 +02:00
minetest.register_node ( " mcl_grindstone:grindstone " , {
2022-06-20 22:31:23 +02:00
description = S ( " Grindstone " ) ,
2022-06-20 21:46:59 +02:00
_tt_help = S ( " Used to disenchant/fix tools " ) ,
2022-08-17 22:47:00 +02:00
_doc_items_longdesc = S ( " Grindstone disenchants tools and armour except for curses, and repairs two items of the same type it is also the weapon smith's work station. " ) ,
2023-07-13 23:43:39 +02:00
_doc_items_usagehelp = S ( " To use the grindstone, rightclick it, Two input slots (on the left) and a single output slot. " ) .. " \n " ..
S ( " To disenchant an item place enchanted item in one of the input slots and take the disenchanted item from the output. " ) .. " \n " ..
S ( " To repair a tool you need a tool of the same type and material, put both items in the input slot and the output slot will combine two items durabilities with 5% bonus. " ) .. " \n " ..
2022-09-10 22:34:31 +02:00
S ( " If both items have enchantments the player will get xp from both items from the disenchant. " ) .. " \ n " ..
S ( " Curses cannot be removed and will be transfered to the new repaired item, if both items have a different curse the curses will be combined. " ) ,
2022-06-20 21:46:59 +02:00
tiles = {
" grindstone_top.png " ,
" grindstone_top.png " ,
" grindstone_side.png " ,
" grindstone_side.png " ,
" grindstone_front.png " ,
" grindstone_front.png "
} ,
drawtype = " nodebox " ,
2022-06-20 22:31:23 +02:00
paramtype2 = " facedir " ,
2022-08-28 15:02:02 +02:00
node_box = node_box ,
2022-08-14 17:49:35 +02:00
selection_box = node_box ,
2022-08-16 23:06:49 +02:00
collision_box = node_box ,
sounds = mcl_sounds.node_sound_stone_defaults ( ) ,
2022-09-10 22:34:31 +02:00
groups = { pickaxey = 1 , deco_block = 1 } ,
2022-08-14 17:49:35 +02:00
2022-08-17 22:47:00 +02:00
after_dig_node = function ( pos , oldnode , oldmetadata , digger )
local meta = minetest.get_meta ( pos )
local meta2 = meta : to_table ( )
meta : from_table ( oldmetadata )
drop_grindstone_items ( pos , meta )
meta : from_table ( meta2 )
end ,
2022-08-14 17:49:35 +02:00
allow_metadata_inventory_take = function ( pos , listname , index , stack , player )
local name = player : get_player_name ( )
if minetest.is_protected ( pos , name ) then
minetest.record_protection_violation ( pos , name )
return 0
else
return stack : get_count ( )
end
end ,
allow_metadata_inventory_put = function ( pos , listname , index , stack , player )
local name = player : get_player_name ( )
if minetest.is_protected ( pos , name ) then
minetest.record_protection_violation ( pos , name )
return 0
elseif listname == " output " then
return 0
else
return stack : get_count ( )
end
end ,
allow_metadata_inventory_move = function ( pos , from_list , from_index , to_list , to_index , count , player )
local name = player : get_player_name ( )
if minetest.is_protected ( pos , name ) then
minetest.record_protection_violation ( pos , name )
return 0
elseif to_list == " output " then
return 0
elseif from_list == " output " and to_list == " input " then
local meta = minetest.get_meta ( pos )
local inv = meta : get_inventory ( )
if inv : get_stack ( to_list , to_index ) : is_empty ( ) then
return count
else
return 0
end
else
return count
end
end ,
on_metadata_inventory_put = function ( pos , listname , index , stack , player )
local meta = minetest.get_meta ( pos )
update_grindstone_slots ( meta )
end ,
on_metadata_inventory_move = function ( pos , from_list , from_index , to_list , to_index , count , player )
local meta = minetest.get_meta ( pos )
if from_list == " output " and to_list == " input " then
local inv = meta : get_inventory ( )
2022-09-10 22:34:31 +02:00
for i = 1 , inv : get_size ( " input " ) do
2022-08-14 17:49:35 +02:00
if i ~= to_index then
local istack = inv : get_stack ( " input " , i )
istack : set_count ( math.max ( 0 , istack : get_count ( ) - count ) )
inv : set_stack ( " input " , i , istack )
end
end
end
update_grindstone_slots ( meta )
end ,
on_metadata_inventory_take = function ( pos , listname , index , stack , player )
local meta = minetest.get_meta ( pos )
if listname == " output " then
2022-08-17 22:47:00 +02:00
local xp_earnt = 0
2022-08-14 17:49:35 +02:00
local inv = meta : get_inventory ( )
local input1 = inv : get_stack ( " input " , 1 )
local input2 = inv : get_stack ( " input " , 2 )
-- Both slots occupied?
if not input1 : is_empty ( ) and not input2 : is_empty ( ) then
2022-08-17 22:47:00 +02:00
-- Get xp earnt from the enchanted items
xp_earnt = calculate_xp ( input1 ) + calculate_xp ( input1 )
2022-09-10 22:34:31 +02:00
input1 : take_item ( 1 )
input2 : take_item ( 1 )
2022-08-14 17:49:35 +02:00
inv : set_stack ( " input " , 1 , input1 )
inv : set_stack ( " input " , 2 , input2 )
else
2022-08-17 22:47:00 +02:00
-- If only one input item
2022-08-14 17:49:35 +02:00
if not input1 : is_empty ( ) then
2022-08-17 22:47:00 +02:00
xp_earnt = calculate_xp ( input1 )
2022-08-14 17:49:35 +02:00
input1 : set_count ( math.max ( 0 , input1 : get_count ( ) - stack : get_count ( ) ) )
inv : set_stack ( " input " , 1 , input1 )
end
if not input2 : is_empty ( ) then
2022-08-17 22:47:00 +02:00
xp_earnt = calculate_xp ( input2 )
2022-08-14 17:49:35 +02:00
input2 : set_count ( math.max ( 0 , input2 : get_count ( ) - stack : get_count ( ) ) )
inv : set_stack ( " input " , 2 , input2 )
end
end
2022-08-17 22:47:00 +02:00
-- Give the player xp
if mcl_experience.throw_xp and xp_earnt > 0 then
mcl_experience.throw_xp ( pos , xp_earnt )
end
2022-08-14 17:49:35 +02:00
elseif listname == " input " then
update_grindstone_slots ( meta )
end
end ,
on_construct = function ( pos )
local meta = minetest.get_meta ( pos )
local inv = meta : get_inventory ( )
inv : set_size ( " input " , 2 )
inv : set_size ( " output " , 1 )
2022-09-10 22:34:31 +02:00
meta : set_string ( " formspec " , grindstone_formspec )
2022-08-14 17:49:35 +02:00
end ,
on_rightclick = function ( pos , node , player , itemstack )
if not player : get_player_control ( ) . sneak then
local meta = minetest.get_meta ( pos )
update_grindstone_slots ( meta )
2022-09-10 22:34:31 +02:00
meta : set_string ( " formspec " , grindstone_formspec )
2022-08-14 17:49:35 +02:00
end
end ,
2022-06-20 21:46:59 +02:00
_mcl_blast_resistance = 6 ,
_mcl_hardness = 2
} )
minetest.register_craft ( {
output = " mcl_grindstone:grindstone " ,
recipe = {
2022-09-10 22:34:31 +02:00
{ " mcl_core:stick " , " mcl_stairs:slab_stone_rough " , " mcl_core:stick " } ,
{ " group:wood " , " " , " group:wood " } ,
2022-06-20 21:46:59 +02:00
}
2022-08-14 17:49:35 +02:00
} )