From 1a874f3ac8f1f1670fa15ac90bb67b0eebc16295 Mon Sep 17 00:00:00 2001 From: Sokomine Date: Wed, 23 Jul 2014 23:41:06 +0200 Subject: [PATCH] added autumn leaves; made the whole functionaly more versatile and less dependent on snow as such --- init.lua | 21 ++- snow_cannon.lua | 6 +- snow_cover_nodes.lua | 87 +++++++++-- snow_on_construct.lua | 352 ++++++++++++++++++++++++------------------ 4 files changed, 300 insertions(+), 166 deletions(-) diff --git a/init.lua b/init.lua index 9f0efed..419ed30 100644 --- a/init.lua +++ b/init.lua @@ -1,16 +1,28 @@ moresnow = {} +-------------------------------------------------------------------------------- +-- Configuration +-------------------------------------------------------------------------------- -- if set to true, fallen autum leaves will be supported just like snow -- The txture and idea for them came from LazyJ. moresnow.enable_autumnleaves = true - +-- the snow cannon allows to create snow +moresnow.enable_snow_cannon = true +-- with this set, the snow cannon can *shoot* snowballs - which will fly a long way; +-- on servers, set this to false +moresnow.crazy_mode = true +-- end of configuration +-------------------------------------------------------------------------------- -- defines the on_construct function for falling/placed snow(balls) dofile(minetest.get_modpath("moresnow")..'/snow_on_construct.lua'); -- devines the 8 types of snow covers: general nodebox snow cover, stairs, slabs, -- outer edge stair, inner edge stair, 3x homedecor shingles/technic cnc shapes dofile(minetest.get_modpath("moresnow")..'/snow_cover_nodes.lua'); +-- which snow node equivals which leaves node? +moresnow.nodetypes = {'snow','autumnleaves'}; +moresnow.build_translation_table(); -- some defines which fascilitate identification of nodes moresnow.c_ignore = minetest.get_content_id( 'ignore' ); @@ -29,8 +41,7 @@ moresnow.c_snow_ramp_inner = minetest.get_content_id( 'moresnow:snow_ramp_inner -- this is important for finding the right snow cover to put on the shape below dofile(minetest.get_modpath("moresnow")..'/snow_analyze_shapes.lua'); -- a snow cannon that shoots snow around -dofile(minetest.get_modpath("moresnow")..'/snow_cannon.lua'); +if( moresnow.enable_snow_cannon ) then + dofile(minetest.get_modpath("moresnow")..'/snow_cannon.lua'); +end - --- TODO: make the autumnleaves from LazyJ working --- TODO: add a function to use this with voxelmanip diff --git a/snow_cannon.lua b/snow_cannon.lua index 3fe25b1..719379d 100644 --- a/snow_cannon.lua +++ b/snow_cannon.lua @@ -149,6 +149,10 @@ moresnow.snow_cannon_update_formspec = function( meta, is_active ) else start = 'start'; end + local button_crazy = ''; + if( moresnow.crazy_mode ) then + button_crazy = "button_exit[6.5,1.5;2,0.5;crazy;crazy]"; + end meta:set_string( 'formspec', "size[10.5,8]".. ( default.gui_bg or '').. @@ -160,7 +164,7 @@ moresnow.snow_cannon_update_formspec = function( meta, is_active ) "button_exit[6.5,0;2,0.5;"..start..";"..start.."]".. "button_exit[6.5,0.5;2,0.5;ordered;ordered]".. "button_exit[6.5,1.0;2,0.5;random;random]".. - "button_exit[6.5,1.5;2,0.5;crazy;crazy]".. + button_crazy.. "label[0,2;Water reservoir:]".. "label[2,2;Fill up with water buckets or ice blocks.]".. "list[current_name;buckets;0,2.5;10,1;]".. diff --git a/snow_cover_nodes.lua b/snow_cover_nodes.lua index e3961ff..3b147be 100644 --- a/snow_cover_nodes.lua +++ b/snow_cover_nodes.lua @@ -2,10 +2,9 @@ -- the general node definition for all these snow tops (only name and nodebox vary) moresnow.register_snow_top = function( node_name, fixed_nodebox ) - minetest.register_node( node_name, { + minetest.register_node( 'moresnow:snow_'..node_name, { description = "Snow", tiles = {"default_snow.png"}, --- tiles = {"moreautumn.png"}, inventory_image = "default_snowball.png", wield_image = "default_snowball.png", is_ground_content = true, @@ -25,24 +24,87 @@ moresnow.register_snow_top = function( node_name, fixed_nodebox ) footstep = {name="default_snow_footstep", gain=0.25}, dug = {name="default_snow_footstep", gain=0.75}, }), - on_construct = moresnow.on_construct, + on_construct = function( pos ) + return moresnow.on_construct_snow( pos, 'moresnow:snow_'..node_name ); + end, + }) + + + if( moresnow.enable_autumnleaves ) then + minetest.register_node( 'moresnow:autumnleaves_'..node_name, { + description = "fallen leaves", + tiles = {"moreautumn.png"}, + inventory_image = "moreautumn.png", + wield_image = "moreautumn.png", + is_ground_content = true, + paramtype = "light", + paramtype2 = "facedir", + buildable_to = true, + drawtype = "nodebox", + node_box = { + -- leveled would not work well in this situation + type = "fixed", + fixed = fixed_nodebox, + }, + drop = "moresnow:autumnleaves", + groups = {falling_node=1, float=1, not_in_creative_inventory=1, snappy=3, flammable=2, leaves=1, not_in_creative_inventory=1}, + sounds = default.node_sound_leaves_defaults(), + on_construct = function( pos ) + return moresnow.on_construct_leaves( pos, 'moresnow:autumnleaves_'..node_name ); + end, + }) + end +end + +-- define the leaves +if( moresnow.enable_autumnleaves ) then + minetest.register_node( "moresnow:autumnleaves", { + description = "fallen leaves", + tiles = {"moreautumn.png"}, + inventory_image = "moreautumn.png", + wield_image = "moreautumn.png", + is_ground_content = true, + paramtype = "light", +-- drawtype = "allfaces_optional", + waving = 1, + buildable_to = true, + leveled = 7, -- can pile up as well + drawtype = "nodebox", + node_box = { + type = "leveled", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.5+2/16, 0.5}, + }, + }, + + groups = {falling_node=1, float=1, snappy=3, flammable=2, leaves=1}, + sounds = default.node_sound_leaves_defaults(), + on_construct = function( pos ) + return moresnow.on_construct_leaves( pos, 'moresnow:autumnleaves' ); + end, }) end + -- now that on_construct has been defined, we can start creating the actual nodes -minetest.registered_nodes[ 'default:snow' ].on_construct = moresnow.on_construct; +minetest.registered_nodes[ 'default:snow' ].on_construct = function( pos ) + return moresnow.on_construct_snow( pos, 'default:snow' ); + end -- the nodebox for this snow node lies one node DEEPER than the node the snow is in; -- thus, nodebox-like nodes covered by snow may look less strange -moresnow.register_snow_top( "moresnow:snow_top", {{-0.5, -1.5, -0.5, 0.5, -1.5+2/16, 0.5}} ); -moresnow.register_snow_top( "moresnow:snow_stair_top", { +moresnow.register_snow_top( "top", {{-0.5, -1.5, -0.5, 0.5, -1.5+2/16, 0.5}} ); +moresnow.register_snow_top( "stair_top", { {-0.5, -1.0, -0.5, 0.5, -1.0+2/16, 0}, {-0.5, -0.5, 0, 0.5, -0.5+2/16, 0.5}, {-0.5, -1.0+2/16, 0-1/32, 0.5, -0.5, 0 }, {-0.5, -1.5, -0.5-1/32, 0.5, -1.0, -0.5}, }); -moresnow.register_snow_top( "moresnow:snow_slab_top", { {-0.5, -1.0, -0.5, 0.5, -1.0+2/16, 0.5}}); -moresnow.register_snow_top( "moresnow:snow_outer_stair_top", { +moresnow.register_snow_top( "slab_top", { {-0.5, -1.0, -0.5, 0.5, -1.0+2/16, 0.5}}); + +-- these shapes exist in moreblocks only +if( minetest.get_modpath( 'moreblocks' )) then + moresnow.register_snow_top( "outer_stair_top", { {-0.5, -1.0, -0.5, 0, -1.0+2/16, 0 }, {-0.5, -0.5, 0, 0, -0.5+2/16, 0.5}, { 0, -1.0, -0.5, 0.5, -1.0+2/16, 0.5}, @@ -53,7 +115,7 @@ moresnow.register_snow_top( "moresnow:snow_outer_stair_top", { {0, -1.0+2/16, 0, 0+1/32, -0.5, 0.5}, {0.5, -1.5, -0.5, 0.5+1/32, -1.0, 0.5}, }); -moresnow.register_snow_top( "moresnow:snow_inner_stair_top", { + moresnow.register_snow_top( "inner_stair_top", { { 0, -1.0, -0.5, 0.5, -1.0+2/16, 0 }, { 0, -0.5, 0, 0.5, -0.5+2/16, 0.5}, @@ -62,6 +124,7 @@ moresnow.register_snow_top( "moresnow:snow_inner_stair_top", { { 0, -1.0+2/16, 0-1/32, 0.5, -0.5, 0 }, { 0, -1.0+2/16, -0.5, 0+1/32, -0.5, 0}, }); +end moresnow.register_shape = function( shape, new_name ) @@ -99,8 +162,8 @@ end -- only add these if either technic (with its cnc machine) or homedecor (with shingles) are installed if( minetest.get_modpath( 'homedecor' ) or minetest.get_modpath( 'technic' )) then - moresnow.register_shape( 1, 'moresnow:snow_ramp_top' ); - moresnow.register_shape( 2, 'moresnow:snow_ramp_outer_top'); - moresnow.register_shape( 3, 'moresnow:snow_ramp_inner_top'); + moresnow.register_shape( 1, 'ramp_top' ); + moresnow.register_shape( 2, 'ramp_outer_top'); + moresnow.register_shape( 3, 'ramp_inner_top'); end diff --git a/snow_on_construct.lua b/snow_on_construct.lua index de15605..fb31722 100644 --- a/snow_on_construct.lua +++ b/snow_on_construct.lua @@ -1,161 +1,217 @@ -moresnow.on_construct = function( pos ) - - local posb = {x=pos.x, y=pos.y-1, z=pos.z}; - local node = minetest.get_node( posb ); - if( node and node.name and minetest.registered_nodes[ node.name ] ) then - local suggested = moresnow.snow_cover[ minetest.get_content_id( node.name )]; - -- if it is some solid node, keep the snow cover - if( not( suggested )) then - -- change the node below if it's some kind of dirt - if( node.name == 'default:dirt_with_grass' or node.name == 'default:dirt' ) then - minetest.set_node( posb, {name="default:dirt_with_snow"}); - end - return; - end +moresnow.translation_table = {} - suggested = minetest.get_name_from_content_id( suggested ); +moresnow.build_translation_table = function() + local shapes = {'top', 'stair_top', 'slab_top', + 'outer_stair_top', 'inner_stair_top', + 'ramp_top', 'ramp_outer_top', 'ramp_inner_top' }; - -- no rule for this node - if( not( suggested )) then - return; - end + for _,t in ipairs(moresnow.nodetypes) do - local p2 = node.param2; - -- homedecor and technic have diffrent ideas about param2... - local p2o = moresnow.snow_param2_offset[ minetest.get_content_id( node.name )]; - if( p2o ) then - p2 = (p2 + p2o ) % 4; - end + moresnow.translation_table[ t ] = {}; - -- if this is a stair or a roof node from homedecor or technics cnc machine; - -- those nodes are all comparable regarding rotation - if( suggested == 'moresnow:snow_stair_top' or suggested == 'moresnow:snow_ramp_top' ) then - if( p2==5 or p2==7 or p2==9 or p2==11 or p2==12 or p2==14 or p2==16 or p2==18 ) then - suggested = 'moresnow:snow_top'; - -- stair turned upside down - elseif( p2==6 or p2==8 or p2==15 or p2==17 or p2==20 or p2==21 or p2==22 or p2==23) then - suggested = 'default:snow'; - -- all these transform into stairs; however, adding the offset (our snow node lies lower than a normal node) would cause chaos - elseif( p2 ==19) then - p2 = 1; - elseif( p2 ==4 ) then - p2 = 2; - elseif( p2 ==13) then - p2 = 3; - elseif( p2 ==10) then - p2 = 0; - -- else it really is a stiar - end - elseif( suggested == 'moresnow:snow_slab_top' ) then - -- vertical slab; tread as a nodebox - if( p2 >= 4 and p2 <= 19 ) then - suggested = 'moresnow:snow_top'; - -- slab turned upside down - elseif( p2 >= 20 and p2 <= 23 ) then - suggested = 'default:snow'; - -- else it's a slab - end - - elseif( suggested == 'moresnow:snow_ramp_outer_top' ) then - -- treat like a nodebox - if( p2>=4 and p2 <= 19 ) then - suggested = 'moresnow:snow_top'; - -- upside-down - elseif( p2 >= 20 and p2 <= 23 ) then - suggested = 'default:snow'; - end - - elseif( suggested == 'moresnow:snow_ramp_inner_top' ) then - -- treat like a nodebox - if( p2>=4 and p2 <= 19 ) then - suggested = 'moresnow:snow_top'; - -- upside-down - elseif( p2 >= 20 and p2 <= 23 ) then - suggested = 'default:snow'; + for _,v in ipairs( shapes ) do + local id1 = minetest.get_content_id( 'moresnow:snow_'..v ); + local id2 = minetest.get_content_id( 'moresnow:'..t..'_'..v ); + if( id1 ) then + moresnow.translation_table[ t ][ id1 ] = id2; end end - -- snow_top is a special node suitable for nodeboxes; BUT: it only looks acceptable if the - -- node below that nodebox/torch/fence/etc is a solid one - if( suggested == 'moresnow:snow_top' ) then - - local node2 = minetest.get_node( {x=pos.x, y=pos.y-2, z=pos.z}); - - if( node2 and node2.name and node2.name == 'default:snow' ) then - if( node2.param2 and node2.param2+8 >= 64 ) then - minetest.set_node( {x=pos.y,y=pos.y-2, z=pos.z}, { name = 'default:snowblock' } ); - return; - else - if( not( node2.param2 )) then - node2.param2 = 8; - end - minetest.set_node( {x=pos.x,y=pos.y-2, z=pos.z}, { name = 'default:snow', param2 = (node2.param2+8) } ); - minetest.remove_node( pos ); - return; - end - end - - -- no information about the node below available - we don't know what to do - if( not( node2 ) or node2.name == 'air' or node2.name == 'ignore' ) then - -- in such a case it helps to drop the snow and let it fall until it hits something - if( node2 and node2.name == 'air' ) then - minetest.remove_node( pos ); - spawn_falling_node( {x=pos.x, y=pos.y-2, z=pos.z}, {name="default:snow"}) - -- else we did not find a sane place for this snow; give up and remove the snow - else - minetest.remove_node( pos ); - end - return; - end - local suggested2 = moresnow.snow_cover[ minetest.get_content_id( node2.name )]; - -- give up - if( not( suggested2 )) then - minetest.remove_node( pos ); - return; - end - suggested2 = minetest.get_name_from_content_id( suggested2 ); - -- if the node below this one can't handle a normal snow cover, we can't put a snow top on our node either - if( suggested2 ~= 'default:snow' ) then - minetest.remove_node( pos ); - return; - end - - end - - if( suggested ) then - local old = minetest.get_node( pos ); - - if( suggested == 'default:snow' ) then - -- if there is snow already, make it higher - if( old and old.name and old.name == suggested ) then - if( old.param2 and old.param2 + 8 >= 64 ) then - minetest.set_node( pos, { name = 'default:snowblock' } ); - -- we are done - the next snow will land on the surface of the snowblock below - return; ---[[ - local above = minetest.get_node( {x=pos.x, y=pos.y+1, z=pos.z} ); - if( above and above.name and above.name == 'air' ) then - minetest.set_node( {x=pos.x, y=pos.y+1, z=pos.z}, { name = 'default:snow', param2 = 8 } ); - return; - end ---]] - elseif( not( old.param2 ) or old.param2 < 1 ) then - p2 = 8; - else - p2 = old.param2 + 1; - end - -- prevent the snow from getting higher - else - p2 = 0; - end - end - if( old and old.name and (old.name ~= suggested or ( old.param2 and old.param2 ~= p2))) then --- swap_node does not seem to affect param2 - minetest.swap_node( pos, { name = suggested, param2 = p2} ); - end + local id1 = minetest.get_content_id( 'default:snow' ); + local id2 = minetest.get_content_id( 'moresnow:'..t ); + if( id1 ) then + moresnow.translation_table[ t ][ id1 ] = id2; end end end + + +moresnow.on_construct_snow = function( pos, falling_node_name ) + + if( not( falling_node_name )) then + falling_node_name = 'default:snow'; + end + + local res = moresnow.on_construct( pos, falling_node_name, 'default:snow', 'snow' ); + if( res ) then + minetest.swap_node( pos, res ); + end +end + + + +moresnow.on_construct_leaves = function( pos, falling_node_name ) +-- TODO: translate the result to the leaves nodes + if( not( falling_node_name )) then + falling_node_name = 'moresnow:autumnleaves'; + end + + local res = moresnow.on_construct( pos, falling_node_name, 'moresnow:autumnleaves', 'autumnleaves' ); + if( res ) then + minetest.swap_node( pos, res ); + end +end + + +-- this function works with content ids because we want it to call for falling +-- snow nodes AND from mapgen (where content ids are at hand) +moresnow.suggest_snow_type = function( node_content_id, p2 ) + + local suggested = moresnow.snow_cover[ node_content_id ]; + -- if it is some solid node, keep the snow cover + if( node_content_id == moresnow.c_snow or not( suggested ) or suggested == moresnow.c_ignore or suggested == moresnow.c_air) then + return { new_id = moresnow.c_snow, param2 = 0 }; + end + + if( not( p2 )) then + p2 = 0; + end + -- homedecor and technic have diffrent ideas about param2... + local p2o = moresnow.snow_param2_offset[ node_content_id ]; + if( p2o ) then + p2 = (p2 + p2o ) % 4; + end + + -- if this is a stair or a roof node from homedecor or technics cnc machine; + -- those nodes are all comparable regarding rotation + if( suggested == moresnow.c_snow_stair + or suggested == moresnow.c_snow_ramp_top ) then + if( p2==5 or p2==7 or p2==9 or p2==11 or p2==12 or p2==14 or p2==16 or p2==18 ) then + suggested = moresnow.c_snow_top; + -- stair turned upside down + elseif( p2==6 or p2==8 or p2==15 or p2==17 or p2==20 or p2==21 or p2==22 or p2==23) then + suggested = moresnow.c_snow; + -- all these transform into stairs; however, adding the offset (our snow node lies lower than a normal node) would cause chaos + elseif( p2 ==19) then + p2 = 1; + elseif( p2 ==4 ) then + p2 = 2; + elseif( p2 ==13) then + p2 = 3; + elseif( p2 ==10) then + p2 = 0; + -- else it really is a stiar + end + elseif( suggested == moresnow.c_snow_slab ) then + -- vertical slab; tread as a nodebox + if( p2 >= 4 and p2 <= 19 ) then + suggested = moresnow.c_snow_top; + -- slab turned upside down + elseif( p2 >= 20 and p2 <= 23 ) then + suggested = moresnow.c_snow; + -- else it's a slab + end + + elseif( suggested == moresnow.c_snow_ramp_outer ) then + -- treat like a nodebox + if( p2>=4 and p2 <= 19 ) then + suggested = moresnow.c_snow_top; + -- upside-down + elseif( p2 >= 20 and p2 <= 23 ) then + suggested = moresnow.c_snow; + end + + elseif( suggested == moresnow.c_snow_ramp_inner ) then + -- treat like a nodebox + if( p2>=4 and p2 <= 19 ) then + suggested = moresnow.c_snow_top; + -- upside-down + elseif( p2 >= 20 and p2 <= 23 ) then + suggested = moresnow.c_snow; + end + end + + return { new_id = suggested, param2 = p2 }; +end + + + + +-- default_name is the name of the node that would be placed in case of a solid underground +-- (usually default:snow) +moresnow.on_construct_select_shape = function( pos, falling_node_name, default_name ) + + -- get the node one below + local node1 = minetest.get_node( {x=pos.x, y=pos.y-1, z=pos.z}); + + -- no information about that node available; give up + if( not(node1) or not(node1.name) or not(minetest.registered_nodes[ node1.name ] )) then + return; + end + + local res = moresnow.suggest_snow_type( minetest.get_content_id( node1.name ), node1.param2 ); + + -- snow_top is a special node suitable for nodeboxes; BUT: it only looks acceptable if the + -- node below that nodebox/torch/fence/etc is a solid one + if( res.new_id == moresnow.c_snow_top ) then + + -- get the node below the node below + local node2 = minetest.get_node( {x=pos.x, y=pos.y-2, z=pos.z}); + + if( node2 and node2.name and node2.name == default_name ) then + return; + end + + -- no information about the node below available - we don't know what to do + if( not( node2 ) or node2.name == 'air' or node2.name == 'ignore' ) then + -- in such a case it helps to drop the snow and let it fall until it hits something + if( node2 and node2.name == 'air' ) then + -- let the snow continue to fall + spawn_falling_node( {x=pos.x, y=pos.y-2, z=pos.z}, {name= default_name}) + end + return { remove_node = true}; + end + local new_id2 = moresnow.snow_cover[ minetest.get_content_id( node2.name )]; + -- if the node below this one can't handle a normal snow cover, we can't put a snow top on our node either + if( not( new_id2 ) or new_id2 ~= moresnow.c_snow) then + return { remove_node = true}; + end + -- else continue with c_snow_top + end + return res; +end + + +-- we need to make sure not to replace the node with the same content +moresnow.on_construct = function( pos, falling_node_name, default_name, node_type ) + + -- get the node we're talking about + local node0 = minetest.get_node( pos ); + + local res = moresnow.on_construct_select_shape( pos, falling_node_name, default_name ); + + if( res and res.remove_node ) then + -- check if we're removing the right node + if( node0 and node0.name and node0.name == falling_node_name) then + minetest.remove_node( pos ); + end + return; -- we're finished + end + + if( not( res ) ) then + -- will be handled by the engine + if( falling_node_name == default_name ) then + return; + -- the falling node was not default:snow (or an aequivalent); but we need default:snow here + elseif( node0 and node0.name and node0.name ~= default_name) then + return { name = default_name, param2 = 0 }; + -- fallback + else + return; + end + end + + if( node_type and moresnow.translation_table[ node_type ] ) then + res.new_id = moresnow.translation_table[ node_type ][ res.new_id ]; + if( not( res.new_id )) then + return; + end + end + local suggested = minetest.get_name_from_content_id( res.new_id ); + if( node0 and node0.name and (node0.name ~= suggested or ( suggested ~= default_name and node0.param2 and node0.param2 ~= res.param2))) then + return { name = suggested, param2 = res.param2}; + end +end