Make many nodes floodable
[minetest_hades/hades_revisited.git] / mods / vines / init.lua
blob53f5a22365b0f25aacd505bfc4b8c15f11f9fece
1 local S = minetest.get_translator("vines")
3 local mod_name = "vines"
4 local average_height = 12
5 local spawn_interval = 90
8 --- VINES GROUPS
9 -- Sideways vines are at the "side" of the node. They attach to the side of nodes
10 local vines_group_side = {vines=1,snappy=3,flammable=2}
11 -- Center vines are in the center of the node. They attach/"hang" from a solid node above
12 local vines_group_center = {vines=2,snappy=3,flammable=2}
13 local tt_surv = S("Needs a tree trunk to survive")
16 local walldir ={}
18 -- Returns true if the node supports vines
19 local supports_vines = function(nodename)
20 local def = minetest.registered_nodes[nodename]
21 -- Rules: 1) walkable 2) full cube OR it's a tree node
22 return minetest.get_item_group(nodename, "tree") ~= 0 or (def.walkable and
23 (def.node_box == nil or def.node_box.type == "regular") and
24 (def.collision_box == nil or def.collision_box.type == "regular"))
25 end
27 --[[ Call this for vines nodes only.
28 Given the pos and node of a vines node, this returns true if the vines are
29 supported and false if the vines are currently floating.
30 Vines are considered “supported” if they face a walkable+solid block or
31 “hang” from a vines node above. ]]
32 local check_vines_supported = function(pos, node)
33 local supported = false
34 local dir = minetest.wallmounted_to_dir(node.param2)
35 local pos1 = vector.add(pos, dir)
36 local node_neighbor = minetest.get_node(pos1)
37 local pos2 = vector.add(pos, {x=0, y=1, z=0})
38 local node2 = minetest.get_node(pos2)
39 local vg = minetest.get_item_group(node.name, "vines")
40 local vg2 = minetest.get_item_group(node2.name, "vines")
41 -- Check if vines are attached to a solid block.
42 -- If ignore, we assume its solid.
43 if (vg == 1) and (node_neighbor.name == "ignore" or supports_vines(node_neighbor.name)) then
44 supported = true
45 elseif (vg == 1) and (dir.y == 0) then
46 -- Vines are not attached, now we check if the vines are “hanging” below another vines block
47 -- of equal orientation.
48 -- Again, ignore means we assume its supported
49 if node2.name == "ignore" or (vg2 == vg and node2.param2 == node.param2) then
50 supported = true
51 end
52 elseif (vg == 2 and supports_vines(node2.name)) then
53 supported = true
54 end
55 return supported
56 end
58 local function get_on_place(centered)
59 -- Restrict placement of vines
60 return function(itemstack, placer, pointed_thing)
61 if pointed_thing.type ~= "node" then
62 -- no interaction possible with entities
63 return itemstack
64 end
66 local under = pointed_thing.under
67 local above = pointed_thing.above
68 local node = minetest.get_node(under)
69 local def = minetest.registered_nodes[node.name]
70 if not def then
71 return itemstack
72 end
73 local groups = def.groups
75 -- Check special rightclick action of pointed node
76 if def and def.on_rightclick then
77 if not placer:get_player_control().sneak then
78 return def.on_rightclick(under, node, placer, itemstack,
79 pointed_thing) or itemstack, false
80 end
81 end
83 local cnode
84 if centered then
85 cnode = minetest.get_node({x=above.x, y=above.y+1, z=above.z})
86 else
87 -- Sideways vines may not be placed on top or below another block
88 if under.y ~= above.y then
89 return itemstack
90 end
91 cnode = node
92 end
93 -- Only place on full cubes
94 if not supports_vines(cnode.name) then
95 -- But centered vines can be placed below centered vines
96 if not (centered and minetest.get_item_group(cnode.name, "vines") == 2) then
97 return itemstack
98 end
99 end
101 local idef = itemstack:get_definition()
102 local itemstack, success = minetest.item_place_node(itemstack, placer, pointed_thing)
104 if success then
105 if idef.sounds and idef.sounds.place then
106 minetest.sound_play(idef.sounds.place, {pos=above, gain=1}, true)
109 return itemstack
113 -- Get vines when using shears
114 local after_dig_node = function(pos, oldnode, oldmetadata, user)
115 local wielded
116 if not user or not user:is_player() then
117 return
119 if user:get_wielded_item() ~= nil then
120 wielded = user:get_wielded_item()
121 else
122 return
124 if minetest.get_item_group(wielded:get_name(), "shears") ~= 0 then
125 local add = true
126 local inv = user:get_inventory()
127 local newstack = ItemStack(oldnode.name)
128 if not inv then
129 add = false
130 elseif minetest.is_creative_enabled(user:get_player_name()) then
131 if inv:contains_item("main", newstack) then
132 add = false
135 if add == true then
136 inv:add_item("main", newstack)
141 -- If vine dug, also dig a “dependant” vine below it.
142 -- A vine is dependant if it hangs from this node and has no supporting block.
143 local on_dig = function(pos, node, digger)
144 local below = {x=pos.x, y=pos.y-1, z=pos.z}
145 local belownode = minetest.get_node(below)
146 minetest.node_dig(pos, node, digger)
147 local vg = minetest.get_item_group(node.name, "vines")
148 local vg2 = minetest.get_item_group(belownode.name, "vines")
149 if vg ~= 0 and vg == vg2 and (not check_vines_supported(below, belownode)) then
150 return minetest.registered_nodes[node.name].on_dig(below, node, digger)
154 local function register_vine(id, def)
155 local paramtype2, drawtype, buildable_to
156 if def.vines_type == "center" then
157 drawtype = "plantlike"
158 buildable_to = false
159 elseif def.vines_type == "side" then
160 paramtype2 = "wallmounted"
161 drawtype = "signlike"
162 buildable_to = true
164 local selection_box = def.selection_box or {
165 type = "wallmounted",
168 local is_centered = def.groups.vines == 2
170 minetest.register_node("vines:"..id, {
171 description = def.description_normal,
172 _tt_help = tt_surv,
173 walkable = false,
174 climbable = true,
175 drop = "",
176 buildable_to = buildable_to,
177 floodable = true,
178 sunlight_propagates = true,
179 paramtype = "light",
180 paramtype2 = paramtype2,
181 tiles = { "vines_"..id..".png" },
182 drawtype = drawtype,
183 inventory_image = "vines_"..id..".png",
184 wield_image = "vines_"..id..".png",
185 groups = def.groups,
186 sounds = hades_sounds.node_sound_leaves_defaults(),
187 selection_box = selection_box,
188 node_placement_prediction = "",
190 on_place = get_on_place(is_centered),
191 on_dig = on_dig,
192 after_dig_node = after_dig_node,
195 if def.description_rotten then
196 local groups_rotten = table.copy(def.groups)
197 groups_rotten.vines_rotten = 1
199 minetest.register_node("vines:"..id.."_rotten", {
200 description = def.description_rotten,
201 walkable = false,
202 climbable = true,
203 drop = "",
204 buildable_to = buildable_to,
205 floodable = true,
206 sunlight_propagates = true,
207 paramtype = "light",
208 paramtype2 = paramtype2,
209 tiles = { "vines_"..id.."_rotten.png" },
210 drawtype = drawtype,
211 inventory_image = "vines_"..id.."_rotten.png",
212 wield_image = "vines_"..id.."_rotten.png",
213 groups = groups_rotten,
214 sounds = hades_sounds.node_sound_leaves_defaults(),
215 selection_box = selection_box,
216 node_placement_prediction = "",
217 on_place = get_on_place(is_centered),
218 on_dig = on_dig,
219 after_dig_node = after_dig_node,
224 register_vine("side", {
225 vines_type = "side",
226 description_normal = S("Jungle Vine"),
227 description_rotten = S("Rotten Jungle Vine"),
228 groups = vines_group_side,
231 register_vine("willow", {
232 vines_type = "side",
233 description_normal = S("Willow Vine"),
234 description_rotten = S("Rotten Willow Vine"),
235 groups = vines_group_side,
238 register_vine("vine", {
239 vines_type = "center",
240 description_normal = S("Cave Vine"),
241 description_rotten = S("Rotten Cave Vine"),
242 groups = vines_group_center,
243 selection_box = {
244 type = "fixed",
245 fixed = {-0.3, -1/2, -0.3, 0.3, 1/2, 0.3},
249 register_vine("root", {
250 vines_type = "center",
251 description_normal = S("Root Vine"),
252 groups = vines_group_center,
253 selection_box = {
254 type = "fixed",
255 fixed = {-1/6, -1/2, -1/6, 1/6, 1/2, 1/6},
259 --ABM
261 minetest.register_abm({
262 label = "Vine rot",
263 nodenames = {"vines:vine", "vines:side", "vines:willow"},
264 interval = 300,
265 chance = 8,
266 action = function(pos, node, active_object_count, active_object_count_wider)
267 if minetest.find_node_near(pos, 5, "group:tree") == nil then
268 walldir = node.param2
269 minetest.add_node(pos, {name=node.name.."_rotten", param2 = walldir})
274 minetest.register_abm({
275 label = "Grow vines",
276 nodenames = {"vines:vine", "vines:side", "vines:willow"},
277 interval = 300,
278 chance = 2,
279 action = function(pos, node, active_object_count, active_object_count_wider)
280 local p = {x=pos.x, y=pos.y-1, z=pos.z}
281 local n = minetest.get_node(p)
282 if n.name == "air" then
283 walldir = node.param2
284 minetest.add_node(p, {name=node.name, param2 = walldir})
289 local function vinedecay_particles(pos, node)
290 local g = minetest.get_item_group(node.name, "vines")
291 local relpos1, relpos2
292 if g == 1 then
293 local dir = minetest.wallmounted_to_dir(node.param2)
294 if dir.x < 0 then
295 relpos1 = { x = -0.45, y = -0.4, z = -0.5 }
296 relpos2 = { x = -0.4, y = 0.4, z = 0.5 }
297 elseif dir.x > 0 then
298 relpos1 = { x = 0.4, y = -0.4, z = -0.5 }
299 relpos2 = { x = 0.45, y = 0.4, z = 0.5 }
300 elseif dir.z < 0 then
301 relpos1 = { x = -0.5, y = -0.4, z = -0.45 }
302 relpos2 = { x = 0.5, y = 0.4, z = -0.4 }
303 elseif dir.z > 0 then
304 relpos1 = { x = -0.5, y = -0.4, z = 0.4 }
305 relpos2 = { x = 0.5, y = 0.4, z = 0.45 }
306 else
307 return
309 elseif g == 2 then
310 relpos1 = { x = -0.25, y = -0.5, z = -0.25 }
311 relpos2 = { x = 0.25, y = 0.5, z = 0.25 }
312 else
313 return
316 minetest.add_particlespawner({
317 amount = math.random(8, 16),
318 time = 0.1,
319 minpos = vector.add(pos, relpos1),
320 maxpos = vector.add(pos, relpos2),
321 minvel = {x=-0.2, y=-0.2, z=-0.2},
322 maxvel = {x=0.2, y=0.1, z=0.2},
323 minacc = {x=0, y=-9.81, z=0},
324 maxacc = {x=0, y=-9.81, z=0},
325 minexptime = 0.1,
326 maxexptime = 0.5,
327 minsize = 0.5,
328 maxsize = 1.0,
329 collisiondetection = true,
330 vertical = false,
331 node = node,
336 minetest.register_abm({
337 label = "Vines decay",
338 nodenames = {"group:vines"},
339 -- A low interval and a high inverse chance spreads the load
340 interval = 2,
341 chance = 5,
343 action = function(pos, node)
344 if not check_vines_supported(pos, node) then
345 on_dig(pos, node)
346 vinedecay_particles(pos, node)
347 minetest.remove_node(pos)
348 minetest.check_for_falling(pos)
350 end,
354 --Craft
356 minetest.register_craftitem("vines:vines", {
357 description = S("Detached Vine"),
358 inventory_image = "vines_item.png",
362 --spawning
363 plantslib:spawn_on_surfaces({
364 avoid_nodes = {"vines:vine"},
365 avoid_radius = 5,
366 spawn_delay = spawn_interval,
367 spawn_plants = {"vines:vine"},
368 spawn_chance = 50,
369 spawn_surfaces = {"hades_core:dirt_with_grass","hades_core:dirt"},
370 spawn_on_bottom = true,
371 plantlife_limit = -0.9,
374 plantslib:spawn_on_surfaces({
375 avoid_nodes = {"vines:vine", "vines:side"},
376 avoid_radius = 3,
377 spawn_delay = spawn_interval,
378 spawn_plants = {"vines:side"},
379 spawn_chance = 50,
380 spawn_surfaces = {"group:leaves"},
381 spawn_on_side = true,
382 near_nodes = {"hades_core:water_source", "hades_trees:jungle_tree"},
383 near_nodes_size = 10,
384 near_nodes_vertical = 5,
385 near_nodes_count = 3,
386 plantlife_limit = -0.9,
389 plantslib:spawn_on_surfaces({
390 spawn_plants = {"vines:willow"},
391 avoid_radius = 3,
392 spawn_delay = spawn_interval,
393 spawn_chance = 50,
394 spawn_surfaces = {"group:leaves"},
395 spawn_on_side = true,
396 near_nodes = {"hades_core:water_source"},
397 near_nodes_size = 7,
398 near_nodes_vertical = 4,
399 near_nodes_count = 3,
400 plantlife_limit = -0.9,
403 -- Shears: jojoa1997's shears
405 minetest.register_tool("vines:shears", {
406 description = S("Shears"),
407 _tt_help = S("Cuts leaves, vines and plants"),
408 inventory_image = "vines_shears.png",
409 wield_image = "vines_shears.png",
410 stack_max = 1,
411 max_drop_level=3,
412 groups = { shears = 1 },
413 tool_capabilities = {
414 full_punch_interval = 1.0,
415 max_drop_level=0,
416 groupcaps={
417 snappy={times={[3]=0.2, [2]=0.5, [1]=1.5}, uses=20, maxlevel=3},
422 minetest.register_craft({
423 output = 'vines:shears',
424 recipe = {
425 {'', 'hades_core:steel_ingot', ''},
426 {'group:stick', 'group:wood', 'hades_core:steel_ingot'},
427 {'', 'group:stick', ''},
431 minetest.register_node("vines:vines_block",{
432 description = S("Vines Block"),
433 sunlight_propagates = true,
434 tiles = {"vines_block.png", "vines_block.png", "vines_block.png"},
435 drawtype = "allfaces_optional",
436 paramtype = "light",
437 groups = {snappy=2,flammable=2 },
438 sounds = hades_sounds.node_sound_leaves_defaults(),
441 minetest.register_craft({
442 output = 'vines:vines_block',
443 recipe = {
444 {'farming:string', '', 'farming:string'},
445 {'', 'group:vines', ''},
446 {'farming:string', '', 'farming:string'},
450 minetest.register_alias("vines:rope", "vines:root")
451 minetest.register_alias("vines:rope_end", "vines:root")
453 minetest.log("action", "[vines] Loaded!")