Erinfest/mods/ITEMS/mcl_grindstone/init.lua

359 lines
12 KiB
Lua

-- Code based from mcl_anvils
mcl_grindstone = {}
local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
local MAX_WEAR = 65535
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]",
})
-- Creates a new item with the wear of the items and custom name
local function create_new_item(name_item, meta, wear)
local new_item = ItemStack(name_item)
if wear ~= nil then
new_item:set_wear(wear)
end
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
-- If an item has an enchanment then remove "_enchanted" from the name
function mcl_grindstone.remove_enchant_name(stack)
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
-- If an input has a curse transfer it to the new item
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
-- 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
-- Add a bit of uniform randomisation
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
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
-- Update the inventory slots of an grindstone node.
-- meta: Metadata of grindstone node
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)
local meta = input1:get_meta()
local new_output
-- Both input slots are occupied
if (not input1:is_empty() and not input2:is_empty()) then
local def1 = input1:get_definition()
local def2 = input2:get_definition()
-- Remove enchant name if they have one
local name1 = mcl_grindstone.remove_enchant_name(input1)
local name2 = mcl_grindstone.remove_enchant_name(input2)
-- Calculate repair
local function calculate_repair(dur1, dur2)
-- Grindstone gives a 5% bonus to durability
local new_durability = (MAX_WEAR - dur1) + (MAX_WEAR - dur2) * 1.05
return math.max(0, math.min(MAX_WEAR, MAX_WEAR - new_durability))
end
-- Check if both are tools and have the same tool type
if def1.type == "tool" and def2.type == "tool" and name1 == name2 then
local new_wear = calculate_repair(input1:get_wear(), input2:get_wear())
local new_item = create_new_item(name1, meta, new_wear)
-- Transfer curses if both items have any
new_output = transfer_curse(input1, new_item)
new_output = transfer_curse(input2, new_output)
else
new_output = ""
end
-- Check if at least one input has an item
-- Check if the item is's an enchanted book or tool
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
local name = mcl_grindstone.remove_enchant_name(input1)
local wear = input1:get_wear()
local new_item = create_new_item(name, meta, wear)
new_output = transfer_curse(input1, new_item)
elseif input1:get_name() == "mcl_enchanting:book_enchanted" then
new_item = create_new_item("mcl_books:book", meta, nil)
new_output = transfer_curse(input1, new_item)
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
local name = mcl_grindstone.remove_enchant_name(input2)
local wear = input2:get_wear()
local new_item = create_new_item(name, meta, wear)
new_output = transfer_curse(input2, new_item)
elseif input2:get_name() == "mcl_enchanting:book_enchanted" then
new_item = create_new_item("mcl_books:book", meta, nil)
new_output = transfer_curse(input2, new_item)
else
new_output = ""
end
end
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
-- Drop any items inside the grindstone if destroyed
local function drop_grindstone_items(pos, meta)
local inv = meta:get_inventory()
for i = 1, inv:get_size("input") do
local stack = inv:get_stack("input", i)
if not stack:is_empty() then
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 }
minetest.add_item(p, stack)
end
end
end
local node_box = {
type = "fixed",
-- created with nodebox editor
fixed = {
{ -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 },
}
}
minetest.register_node("mcl_grindstone:grindstone", {
description = S("Grindstone"),
_tt_help = S("Used to disenchant/fix tools"),
_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."),
_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" ..
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."),
tiles = {
"grindstone_top.png",
"grindstone_top.png",
"grindstone_side.png",
"grindstone_side.png",
"grindstone_front.png",
"grindstone_front.png"
},
drawtype = "nodebox",
paramtype2 = "facedir",
node_box = node_box,
selection_box = node_box,
collision_box = node_box,
sounds = mcl_sounds.node_sound_stone_defaults(),
groups = { pickaxey = 1, deco_block = 1 },
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,
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()
for i = 1, inv:get_size("input") do
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
local xp_earnt = 0
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
-- Get xp earnt from the enchanted items
xp_earnt = calculate_xp(input1) + calculate_xp(input1)
input1:take_item(1)
input2:take_item(1)
inv:set_stack("input", 1, input1)
inv:set_stack("input", 2, input2)
else
-- If only one input item
if not input1:is_empty() then
xp_earnt = calculate_xp(input1)
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
xp_earnt = calculate_xp(input2)
input2:set_count(math.max(0, input2:get_count() - stack:get_count()))
inv:set_stack("input", 2, input2)
end
end
-- Give the player xp
if mcl_experience.throw_xp and xp_earnt > 0 then
mcl_experience.throw_xp(pos, xp_earnt)
end
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)
meta:set_string("formspec", grindstone_formspec)
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)
meta:set_string("formspec", grindstone_formspec)
end
end,
_mcl_blast_resistance = 6,
_mcl_hardness = 2
})
minetest.register_craft({
output = "mcl_grindstone:grindstone",
recipe = {
{ "mcl_core:stick", "mcl_stairs:slab_stone_rough", "mcl_core:stick" },
{ "group:wood", "", "group:wood" },
}
})