diff --git a/DEV_GROUPS.md b/DEV_GROUPS.md index c31c6770..ba939b56 100644 --- a/DEV_GROUPS.md +++ b/DEV_GROUPS.md @@ -106,7 +106,17 @@ Also, never use `handy` and `oddly_breakable_by_hand` at the same time. * `special_magnocompass_node_handling=1`: Node will handle placing a magno compass in a special way (see `rp_nav`) * `seed`: A farming item that can be planted on the ground to spawn a plant that will grow over time. Usually this is a seed, but it does not have to be. -* `_attached_node_top=1`: Node attaches to the top of another node. If the node above disappears, the node itself detaches +* `_attached_node_top=1`: Node attaches to the top of another node or itself. If the node above disappears, the node itself detaches +* `_attached_node_bottom=1`: Node attaches to the bottom of another node or itself. If the node below disappears, the node itself detaches + +#### Note about the `_attached_node_*` groups + +These groups are a more specialized variant of the built-in `attached_node` group. + +They are specifically designed for nodes that vertically stack and attach to each other, like vines or thistles. +The unique thing about these groups is that breaking the support of this node will cause a cascade. +Unlike `attached_node`, they also work if the node is not `walkable`. Use these groups when a standard +`attached_node` does not suffice. ### Node categorization diff --git a/mods/rp_attached/init.lua b/mods/rp_attached/init.lua index b02eeeb3..c249d893 100644 --- a/mods/rp_attached/init.lua +++ b/mods/rp_attached/init.lua @@ -10,6 +10,13 @@ rp_attached.detach_from_node = function(pos, digger) local at = minetest.get_item_group(belownode.name, "_attached_node_top") == 1 if at then util.dig_down(pos, belownode, digger) + return + end + local above = vector.add(pos, vector.new(0,1,0)) + local abovenode = minetest.get_node(above) + local ab = minetest.get_item_group(abovenode.name, "_attached_node_bottom") == 1 + if ab then + util.dig_up(pos, abovenode, digger) end end diff --git a/mods/rp_default/nodes_plants.lua b/mods/rp_default/nodes_plants.lua index 909822be..cfc59edb 100644 --- a/mods/rp_default/nodes_plants.lua +++ b/mods/rp_default/nodes_plants.lua @@ -463,8 +463,9 @@ minetest.register_node( walkable = false, floodable = true, damage_per_second = 1, - groups = {snappy = 3, dig_immediate = 3, falling_node = 1, plant = 1, immortal_item = 1}, + groups = {snappy = 3, dig_immediate = 3, _attached_node_bottom = 1, plant = 1, immortal_item = 1}, sounds = rp_sounds.node_sound_plant_defaults(), + node_placement_prediction = "", after_dig_node = function(pos, node, metadata, digger) util.dig_up(pos, node, digger) end, @@ -472,5 +473,53 @@ minetest.register_node( minetest.add_item(pos, "rp_default:thistle") util.dig_up(pos, oldnode, nil, "rp_default:thistle") end, + on_blast = function(pos) + -- Destroy the blasted node and detach thistles above + local oldnode = minetest.get_node(pos) + minetest.remove_node(pos) + util.dig_up(pos, oldnode) + end, + on_place = function(itemstack, placer, pointed_thing) + -- Boilerplate to handle pointed node handlers + local handled, handled_itemstack = util.on_place_pointed_node_handler(itemstack, placer, pointed_thing) + if handled then + return handled_itemstack + end + + -- Find position to place thistle at + local place_in, place_floor = util.pointed_thing_to_place_pos(pointed_thing) + if place_in == nil then + rp_sounds.play_place_failed_sound(placer) + return itemstack + end + local floornode = minetest.get_node(place_floor) + local floordef = minetest.registered_nodes[floornode.name] + + -- Floor must be a walkable node or another thistle + if not (floornode.name == "rp_default:thistle" or (floordef and floordef.walkable)) then + rp_sounds.play_place_failed_sound(placer) + return itemstack + end + + -- Check protection + if minetest.is_protected(place_in, placer:get_player_name()) and + not minetest.check_player_privs(placer, "protection_bypass") then + minetest.record_protection_violation(pos, placer:get_player_name()) + return itemstack + end + + -- Place thistle + local newnode = {name = itemstack:get_name()} + minetest.set_node(place_in, newnode) + rp_sounds.play_node_sound(place_in, newnode, "place") + + -- Reduce item count + if not minetest.is_creative_enabled(placer:get_player_name()) then + itemstack:take_item() + end + + return itemstack + end, + })