local S = minetest.get_translator("hades_vines") local mod_name = "hades_vines" local average_height = 12 local spawn_interval = 90 --- VINES GROUPS -- Sideways vines are at the "side" of the node. They attach to the side of nodes local vines_group_side = {vines=1,snappy=3,flammable=2} -- Center vines are in the center of the node. They attach/"hang" from a solid node above local vines_group_center = {vines=2,snappy=3,flammable=2} local tt_surv = S("Needs a tree trunk to survive") local walldir ={} -- Returns true if the node supports vines local supports_vines = function(nodename) local def = minetest.registered_nodes[nodename] if not def then return true end -- Rules: 1) walkable 2) full cube OR it's a tree node return minetest.get_item_group(nodename, "tree") ~= 0 or (def.walkable and (def.node_box == nil or def.node_box.type == "regular") and (def.collision_box == nil or def.collision_box.type == "regular")) end --[[ Call this for vines nodes only. Given the pos and node of a vines node, this returns true if the vines are supported and false if the vines are currently floating. Vines are considered “supported” if they face a walkable+solid block or “hang” from a vines node above. ]] local check_vines_supported = function(pos, node) local supported = false local dir = minetest.wallmounted_to_dir(node.param2) local pos1 = vector.add(pos, dir) local node_neighbor = minetest.get_node(pos1) local pos2 = vector.add(pos, {x=0, y=1, z=0}) local node2 = minetest.get_node(pos2) local vg = minetest.get_item_group(node.name, "vines") local vg2 = minetest.get_item_group(node2.name, "vines") -- Check if vines are attached to a solid block. -- If ignore, we assume its solid. if (vg == 1) and (node_neighbor.name == "ignore" or supports_vines(node_neighbor.name)) then supported = true elseif (vg == 1) and (dir.y == 0) then -- Vines are not attached, now we check if the vines are “hanging” below another vines block -- of equal orientation. -- Again, ignore means we assume its supported if node2.name == "ignore" or (vg2 == vg and node2.param2 == node.param2) then supported = true end elseif (vg == 2 and (supports_vines(node2.name) or vg2 == 2)) then supported = true end return supported end local function get_on_place(centered) -- Restrict placement of vines return function(itemstack, placer, pointed_thing) if pointed_thing.type ~= "node" then -- no interaction possible with entities return itemstack end local under = pointed_thing.under local above = pointed_thing.above local node = minetest.get_node(under) local def = minetest.registered_nodes[node.name] if not def then return itemstack end local groups = def.groups -- Check special rightclick action of pointed node if def and def.on_rightclick then if not placer:get_player_control().sneak then return def.on_rightclick(under, node, placer, itemstack, pointed_thing) or itemstack, false end end local cnode if centered then cnode = minetest.get_node({x=above.x, y=above.y+1, z=above.z}) else -- Sideways vines may not be placed on top or below another block if under.y ~= above.y then return itemstack end cnode = node end -- Only place on full cubes if not supports_vines(cnode.name) then -- But centered vines can be placed below centered vines if not (centered and minetest.get_item_group(cnode.name, "vines") == 2) then return itemstack end end local idef = itemstack:get_definition() local itemstack, success = minetest.item_place_node(itemstack, placer, pointed_thing) if success then if idef.sounds and idef.sounds.place then minetest.sound_play(idef.sounds.place, {pos=above, gain=1}, true) end end return itemstack end end -- Get vines when using shears local after_dig_node = function(pos, oldnode, oldmetadata, user) local wielded if not user or not user:is_player() then return end if user:get_wielded_item() ~= nil then wielded = user:get_wielded_item() else return end if minetest.get_item_group(wielded:get_name(), "shears") ~= 0 then local add = true local inv = user:get_inventory() local newstack = ItemStack(oldnode.name) if not inv then add = false elseif minetest.is_creative_enabled(user:get_player_name()) then if inv:contains_item("main", newstack) then add = false end end if add == true then inv:add_item("main", newstack) end end end -- If vine dug, also dig a “dependant” vine below it. -- A vine is dependant if it hangs from this node and has no supporting block. local on_dig = function(pos, node, digger) local below = {x=pos.x, y=pos.y-1, z=pos.z} local belownode = minetest.get_node(below) minetest.node_dig(pos, node, digger) local vg = minetest.get_item_group(node.name, "vines") local vg2 = minetest.get_item_group(belownode.name, "vines") if vg ~= 0 and vg == vg2 and (not check_vines_supported(below, belownode)) then return minetest.registered_nodes[node.name].on_dig(below, node, digger) end end local function register_vine(id, def) local paramtype2, drawtype, buildable_to, on_rotate if def.vines_type == "center" then drawtype = "plantlike" buildable_to = false elseif def.vines_type == "side" then paramtype2 = "wallmounted" drawtype = "signlike" buildable_to = true on_rotate = false end local selection_box = def.selection_box or { type = "wallmounted", } local is_centered = def.groups.vines == 2 local mnext if def.description_rotten then mnext = "hades_vines:"..id.."_rotten" end minetest.register_node("hades_vines:"..id, { description = def.description_normal, _tt_help = tt_surv, walkable = false, climbable = true, drop = "", buildable_to = buildable_to, floodable = true, sunlight_propagates = true, paramtype = "light", paramtype2 = paramtype2, tiles = { "hades_vines_"..id..".png", "hades_vines_"..id..".png", "blank.png" }, drawtype = drawtype, inventory_image = "hades_vines_"..id..".png", wield_image = "hades_vines_"..id..".png", groups = def.groups, sounds = hades_sounds.node_sound_leaves_defaults(), selection_box = selection_box, node_placement_prediction = "", on_place = get_on_place(is_centered), on_dig = on_dig, on_rotate = on_rotate, after_dig_node = after_dig_node, _hades_magic_next = mnext, }) if def.description_rotten then local groups_rotten = table.copy(def.groups) groups_rotten.vines_rotten = 1 minetest.register_node("hades_vines:"..id.."_rotten", { description = def.description_rotten, walkable = false, climbable = true, drop = "", buildable_to = buildable_to, floodable = true, sunlight_propagates = true, paramtype = "light", paramtype2 = paramtype2, tiles = { "hades_vines_"..id.."_rotten.png", "hades_vines_"..id.."_rotten.png", "blank.png" }, drawtype = drawtype, inventory_image = "hades_vines_"..id.."_rotten.png", wield_image = "hades_vines_"..id.."_rotten.png", groups = groups_rotten, sounds = hades_sounds.node_sound_leaves_defaults(), selection_box = selection_box, node_placement_prediction = "", on_place = get_on_place(is_centered), on_dig = on_dig, after_dig_node = after_dig_node, _hades_magic_next = "hades_vines:"..id, }) end end register_vine("jungle", { vines_type = "side", description_normal = S("Tropical Vine"), description_rotten = S("Rotten Tropical Vine"), groups = vines_group_side, }) register_vine("willow", { vines_type = "side", description_normal = S("Willow Vine"), description_rotten = S("Rotten Willow Vine"), groups = vines_group_side, }) register_vine("cave", { vines_type = "center", description_normal = S("Cave Vine"), description_rotten = S("Rotten Cave Vine"), groups = vines_group_center, selection_box = { type = "fixed", fixed = {-0.3, -1/2, -0.3, 0.3, 1/2, 0.3}, }, }) register_vine("root", { vines_type = "center", description_normal = S("Root Vine"), groups = vines_group_center, selection_box = { type = "fixed", fixed = {-1/6, -1/2, -1/6, 1/6, 1/2, 1/6}, }, }) --ABM minetest.register_abm({ label = "Vine rot", nodenames = {"hades_vines:cave", "hades_vines:jungle", "hades_vines:willow"}, interval = 300, chance = 8, action = function(pos, node, active_object_count, active_object_count_wider) if minetest.find_node_near(pos, 5, "group:tree") == nil then walldir = node.param2 minetest.add_node(pos, {name=node.name.."_rotten", param2 = walldir}) end end }) minetest.register_abm({ label = "Grow vines", nodenames = {"hades_vines:cave", "hades_vines:jungle", "hades_vines:willow"}, interval = 300, chance = 2, action = function(pos, node, active_object_count, active_object_count_wider) local p = {x=pos.x, y=pos.y-1, z=pos.z} local n = minetest.get_node(p) if n.name == "air" then minetest.add_node(p, {name=node.name, param2=node.param2}) end end }) local function vinedecay_particles(pos, node) local g = minetest.get_item_group(node.name, "vines") local relpos1, relpos2 if g == 1 then local dir = minetest.wallmounted_to_dir(node.param2) if dir.x < 0 then relpos1 = { x = -0.45, y = -0.4, z = -0.5 } relpos2 = { x = -0.4, y = 0.4, z = 0.5 } elseif dir.x > 0 then relpos1 = { x = 0.4, y = -0.4, z = -0.5 } relpos2 = { x = 0.45, y = 0.4, z = 0.5 } elseif dir.z < 0 then relpos1 = { x = -0.5, y = -0.4, z = -0.45 } relpos2 = { x = 0.5, y = 0.4, z = -0.4 } elseif dir.z > 0 then relpos1 = { x = -0.5, y = -0.4, z = 0.4 } relpos2 = { x = 0.5, y = 0.4, z = 0.45 } else return end elseif g == 2 then relpos1 = { x = -0.25, y = -0.5, z = -0.25 } relpos2 = { x = 0.25, y = 0.5, z = 0.25 } else return end minetest.add_particlespawner({ amount = math.random(8, 16), time = 0.1, minpos = vector.add(pos, relpos1), maxpos = vector.add(pos, relpos2), minvel = {x=-0.2, y=-0.2, z=-0.2}, maxvel = {x=0.2, y=0.1, z=0.2}, minacc = {x=0, y=-9.81, z=0}, maxacc = {x=0, y=-9.81, z=0}, minexptime = 0.1, maxexptime = 0.5, minsize = 0.5, maxsize = 1.0, collisiondetection = true, vertical = false, node = node, }) end minetest.register_abm({ label = "Vines decay", nodenames = {"group:vines"}, -- A low interval and a high inverse chance spreads the load interval = 2, chance = 5, action = function(pos, node) if not check_vines_supported(pos, node) then on_dig(pos, node) vinedecay_particles(pos, node) minetest.remove_node(pos) minetest.check_for_falling(pos) end end, }) -- Spawn vines hades_plantslib.spawn_on_surfaces({ label = "Spawn cave vines", avoid_nodes = {"hades_vines:cave"}, avoid_radius = 5, spawn_delay = spawn_interval, spawn_plants = {"hades_vines:cave"}, spawn_chance = 50, spawn_surfaces = {"hades_core:dirt_with_grass","hades_core:dirt_with_grass_l1","hades_core:dirt_with_grass_l2","hades_core:dirt_with_grass_l3","hades_core:dirt"}, spawn_on_bottom = true, }) hades_plantslib.spawn_on_surfaces({ label = "Spawn tropical vines", avoid_nodes = {"hades_vines:cave", "hades_vines:jungle"}, avoid_radius = 3, spawn_delay = spawn_interval, spawn_plants = {"hades_vines:jungle"}, spawn_chance = 50, spawn_surfaces = {"group:leaves"}, spawn_on_side = true, near_nodes = {"hades_core:water_source", "hades_trees:jungle_tree"}, near_nodes_size = 10, near_nodes_vertical = 5, near_nodes_count = 3, }) hades_plantslib.spawn_on_surfaces({ label = "Spawn willow vines", spawn_plants = {"hades_vines:willow"}, avoid_radius = 3, spawn_delay = spawn_interval, spawn_chance = 50, spawn_surfaces = {"group:leaves"}, spawn_on_side = true, near_nodes = {"hades_core:water_source"}, near_nodes_size = 7, near_nodes_vertical = 4, near_nodes_count = 3, }) -- Shears: jojoa1997's shears minetest.register_tool("hades_vines:shears", { description = S("Shears"), _tt_help = S("Cuts leaves, vines and plants"), inventory_image = "hades_vines_shears.png", wield_image = "hades_vines_shears.png", stack_max = 1, max_drop_level=3, groups = { shears = 1 }, tool_capabilities = { full_punch_interval = 1.0, max_drop_level=0, groupcaps={ snappy={times={[3]=0.2, [2]=0.5, [1]=1.5}, uses=20, maxlevel=3}, } }, }) minetest.register_craft({ output = 'hades_vines:shears', recipe = { {'', 'hades_core:steel_ingot', ''}, {'group:stick', 'group:wood', 'hades_core:steel_ingot'}, {'', 'group:stick', ''}, } }) minetest.register_node("hades_vines:vines_block",{ description = S("Vines Block"), sunlight_propagates = true, tiles = {"hades_vines_block.png"}, drawtype = "allfaces_optional", paramtype = "light", groups = {snappy=2,flammable=2 }, sounds = hades_sounds.node_sound_leaves_defaults(), }) minetest.register_craft({ output = 'hades_vines:vines_block', recipe = { {'hades_farming:string', '', 'hades_farming:string'}, {'', 'group:vines', ''}, {'hades_farming:string', '', 'hades_farming:string'}, } }) minetest.log("action", "[hades_vines] loaded!")