-- Magicalities Wands magicalities.wands = {} local transform_recipes = { ["mg_table"] = {result = "magicalities:arcane_table", requirements = nil} } local wandcaps = { full_punch_interval = 1.0, max_drop_level = 0, groupcaps = {}, damage_groups = {fleshy = 2}, } local randparticles = PcgRandom(os.clock()) local function align(len) local str = "" for i = 1, len do str = str.."\t" end return str end -- Update wand's description function magicalities.wands.update_wand_desc(stack) local meta = stack:get_meta() local data_table = minetest.deserialize(meta:get_string("contents")) local wanddata = minetest.registered_items[stack:get_name()] local description = wanddata.description local capcontents = wanddata["_cap_max"] or 15 local strbld = description.."\n" local longest_desc = 0 for _,data in pairs(magicalities.elements) do if not data.inheritance then local len = #data.description if len > longest_desc then longest_desc = len end end end local elems = {} for elem, amount in pairs(data_table) do local dataelem = magicalities.elements[elem] if amount > 0 then elems[#elems + 1] = minetest.colorize(dataelem.color, dataelem.description.." ").. align(longest_desc * 2 - #dataelem.description).. amount.."/"..capcontents end end table.sort(elems) strbld = strbld .. table.concat(elems, "\n") meta:set_string("description", strbld) end -- Ensure wand has contents function magicalities.wands.wand_has_contents(stack, requirements) local meta = stack:get_meta() local data_table = minetest.deserialize(meta:get_string("contents")) if not data_table then return false end for name, count in pairs(requirements) do if not data_table[name] or data_table[name] < count then return false end end return true end -- Take wand contents function magicalities.wands.wand_take_contents(stack, to_take) local meta = stack:get_meta() local data_table = minetest.deserialize(meta:get_string("contents")) for name, count in pairs(to_take) do if not data_table[name] or data_table[name] - count < 0 then return nil end data_table[name] = data_table[name] - count end local data_res = minetest.serialize(data_table) meta:set_string("contents", data_res) return stack end -- Add wand contents function magicalities.wands.wand_insert_contents(stack, to_put) local meta = stack:get_meta() local data_table = minetest.deserialize(meta:get_string("contents")) local cap = minetest.registered_items[stack:get_name()]["_cap_max"] local leftover = {} for name, count in pairs(to_put) do if data_table[name] then if data_table[name] + count > cap then data_table[name] = cap leftover[name] = (data_table[name] + count) - cap else data_table[name] = data_table[name] + count end end end local data_res = minetest.serialize(data_table) meta:set_string("contents", data_res) return stack, leftover end -- Can add wand contents function magicalities.wands.wand_insertable_contents(stack, to_put) local meta = stack:get_meta() local data_table = minetest.deserialize(meta:get_string("contents")) local cap = minetest.registered_items[stack:get_name()]["_cap_max"] local insertable = {} for name, count in pairs(to_put) do if data_table[name] then if data_table[name] + count < cap + 1 then insertable[name] = count end end end return insertable end -- Initialize wand metadata local function initialize_wand(stack) local data_table = {} for name, data in pairs(magicalities.elements) do if not data.inheritance then data_table[name] = 0 end end local meta = stack:get_meta() meta:set_string("contents", minetest.serialize(data_table)) end local function wand_action(itemstack, placer, pointed_thing) if not pointed_thing.type == "node" then return itemstack end local node = minetest.get_node(pointed_thing.under) local imeta = itemstack:get_meta() -- Initialize wand metadata if imeta:get_string("contents") == nil or imeta:get_string("contents") == "" then initialize_wand(itemstack) magicalities.wands.update_wand_desc(itemstack) end -- Replacement local to_replace = nil for grp, result in pairs(transform_recipes) do if minetest.get_item_group(node.name, grp) > 0 then to_replace = result break end end -- Call on_rightclick on the node instead if it cannot be replaced if not to_replace then local nodedef = minetest.registered_nodes[node.name] if nodedef.on_rightclick then itemstack = nodedef.on_rightclick(pointed_thing.under, node, placer, itemstack, pointed_thing) end return itemstack end if to_replace.requirements then if not magicalities.wands.wand_has_contents(itemstack, to_replace.requirements) then return itemstack end itemstack = magicalities.wands.wand_take_contents(itemstack, to_replace.requirements) magicalities.wands.update_wand_desc(itemstack) end minetest.swap_node(pointed_thing.under, {name = to_replace.result, param1 = node.param1, param2 = node.param2}) local spec = minetest.registered_nodes[to_replace.result] if spec.on_construct then spec.on_construct(pointed_thing.under) end return itemstack end local function use_wand(itemstack, user, pointed_thing) local imeta = itemstack:get_meta() -- Initialize wand metadata if imeta:get_string("contents") == nil or imeta:get_string("contents") == "" then initialize_wand(itemstack) magicalities.wands.update_wand_desc(itemstack) end -- Calculate velocity local dir = user:get_look_dir() local vel = {x=0,y=0,z=0} vel.x = dir.x * 16 vel.y = dir.y * 16 vel.z = dir.z * 16 -- Calculate position local pos = user:get_pos() pos.x = pos.x + (dir.x * 2) pos.y = pos.y + (dir.y * 2) + 1.5 pos.z = pos.z + (dir.z * 2) for i = 1, 16 do -- Deviation local relvel = {x=0,y=0,z=0} relvel.x = vel.x + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) relvel.y = vel.y + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) relvel.z = vel.z + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) minetest.add_particle({ pos = pos, velocity = relvel, acceleration = relvel, expirationtime = 1, size = 4, collisiondetection = true, collision_removal = true, texture = "magicalities_spark.png", -- animation = {Tile Animation definition}, glow = 2 }) end magicalities.wands.update_wand_desc(itemstack) return itemstack end function magicalities.wands.register_wand(name, data) local mod = minetest.get_current_modname() minetest.register_tool(mod..":wand_"..name, { description = data.description, inventory_image = data.image, tool_capabilities = wandcaps, stack_max = 1, _cap_max = data.wand_cap, on_use = use_wand, on_place = wand_action, groups = {wand = 1} }) end