453 lines
13 KiB
Lua
453 lines
13 KiB
Lua
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!")
|