From a75a700c9a9135e4b24010346628ccd9ba8a5551 Mon Sep 17 00:00:00 2001 From: Sokomine Date: Wed, 23 Jul 2014 01:51:17 +0200 Subject: [PATCH] moved functionality into seperate files --- init.lua | 437 +--------------------------------------- snow_analyze_shapes.lua | 161 +++++++++++++++ snow_cover_nodes.lua | 106 ++++++++++ snow_on_construct.lua | 161 +++++++++++++++ 4 files changed, 437 insertions(+), 428 deletions(-) create mode 100644 snow_analyze_shapes.lua create mode 100644 snow_cover_nodes.lua create mode 100644 snow_on_construct.lua diff --git a/init.lua b/init.lua index 6efae30..db3ff21 100644 --- a/init.lua +++ b/init.lua @@ -1,434 +1,15 @@ moresnow = {} --- 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, { - description = "Snow", - tiles = {"default_snow.png"}, --- tiles = {"moreautumn.png"}, - inventory_image = "default_snowball.png", - wield_image = "default_snowball.png", - is_ground_content = true, - paramtype = "light", - paramtype2 = "facedir", - buildable_to = true, - drawtype = "nodebox", - freezemelt = "default:water_flowing", - node_box = { - -- leveled would not work well in this situation - type = "fixed", - fixed = fixed_nodebox, - }, - drop = "default:snow", - groups = {crumbly=3,falling_node=1, melts=1, float=1, not_in_creative_inventory=1}, - sounds = default.node_sound_dirt_defaults({ - footstep = {name="default_snow_footstep", gain=0.25}, - dug = {name="default_snow_footstep", gain=0.75}, - }), - on_construct = moresnow.on_construct, - }) -end - - -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 - - suggested = minetest.get_name_from_content_id( suggested ); - - -- no rule for this node - if( not( suggested )) then - return; - end - - 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 - - -- 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'; - 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 - end - 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; - --- 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", { - {-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", { - {-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}, - - {-0.5, -1.0+2/16, 0-1/32, 0, -0.5, 0 }, - {-0.5, -1.5, -0.5-1/32, 0.5, -1.0, -0.5}, - - {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", { - { 0, -1.0, -0.5, 0.5, -1.0+2/16, 0 }, - - { 0, -0.5, 0, 0.5, -0.5+2/16, 0.5}, - {-0.5, -0.5, -0.5, 0, -0.5+2/16, 0.5}, - - { 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}, - }); - - -moresnow.register_shape = function( shape, new_name ) - - local detail = 16; - - local slopeboxedge = {}; - for i = 0, detail-1 do - - if( shape==1 ) then -- slope; normal roof shingles - slopeboxedge[i+1]={ -0.5, (i/detail)-1.5+(1.25/detail), (i/detail)-0.5, - 0.5, (i/detail)-1.5+(1.25/detail)+(1/detail), (i/detail)-0.5+(1/detail)}; - - elseif( shape==2 ) then -- outer corner - slopeboxedge[i+1]={ -0.5, (i/detail)-1.5+(1.25/detail), (i/detail)-0.5, - 0.5-(i/detail), (i/detail)-1.5+(1.25/detail)+(1/detail), (i/detail)-0.5+(1/detail)}; - - slopeboxedge[i+detail*1]={ 0.5-(i/detail), (i/detail)-1.5+(1.25/detail)-(1/detail), 0.5, - 0.5-(i/detail)+(1/detail), (i/detail)-1.5+(1.25/detail), -0.5+(i/detail) }; - - - elseif( shape==3 ) then -- inner corner - local v = detail-i; - slopeboxedge[i+1]={ (i/detail)-0.5, (v/detail)-1.5+(1.25/detail)-(1/detail), -0.5+(1/detail-(1/detail)), - (i/detail)-0.5+(1/detail), (v/detail)-1.5+(1.25/detail), 0.5-(i/detail) }; - - slopeboxedge[i+detail*1]={ 0.5, (v/detail)-1.5+(1.25/detail), 0.5-(i/detail), - -0.5+(i/detail), (v/detail)-1.5+(1.25/detail)+(1/detail), 0.5-(i/detail)+(1/detail) }; - end - end - - moresnow.register_snow_top( new_name, slopeboxedge ); -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'); -end - - --- find out which nodes are stairs and which are slabs (those are handled diffrently by our snow here); --- this is necessary in order to determine which shape the snow on top of the node will take --- (of course this only works for a few shapes and does not even take rotation into consideration) -moresnow.snow_cover = {}; - --- homedecor and technic did not settle on common param2 interpretation :-( -moresnow.snow_param2_offset = {}; - --- homedecor 3d shingles and technic cnc items are handled here -moresnow.identify_special_slopes = function( new_name, homedecor_prefix, technic_postfix, param2_offset ) - -- these nodes are only supported if homedecor and/or technic are installed - local c_new_snow_node = minetest.get_content_id( new_name ); - if( not( c_new_snow_node )) then - return; - end - - local c_ignore = minetest.get_content_id( 'ignore' ); - - local homedecor_materials = {'terracotta','wood','asphalt'}; - local technic_materials = {'dirt','wood','stone','cobble','brick','sandstone','leaves', - 'tree','steelblock','bronzeblock','stainless_steel','marble','granite'}; - - for _,v in ipairs( homedecor_materials ) do - local id = minetest.get_content_id( homedecor_prefix..v ); - -- the node has to be registered at this point; thus, the soft-dependency on homedecor and technic - if( id and id ~= c_ignore ) then - moresnow.snow_cover[ id ] = c_new_snow_node; - end - end - for _,v in ipairs( technic_materials ) do - local prefix = 'default:'; - if( v=='stainless_steel' or v=='marble' or v=='granite' ) then - prefix = 'technic:'; - end - - local id = minetest.get_content_id( prefix..v..technic_postfix ); - -- the node has to be registered at this point; thus, the soft-dependency on homedecor and technic - if( id and id ~= c_ignore ) then - moresnow.snow_cover[ id ] = c_new_snow_node; - -- homedecor and technic use diffrent param2 for the same shape - if( param2_offset ) then - moresnow.snow_param2_offset[ id ] = param2_offset; - end - end - end -end - --- identify stairs and slabs (roughly!) by their nodeboxes -moresnow.identify_stairs_and_slabs = function() - - moresnow.identify_special_slopes( 'moresnow:snow_ramp_top', 'homedecor:shingle_side_', '_technic_cnc_slope', 0 ); - moresnow.identify_special_slopes( 'moresnow:snow_ramp_outer_top', 'homedecor:shingle_outer_corner_', '_technic_cnc_slope_edge', 1 ); - moresnow.identify_special_slopes( 'moresnow:snow_ramp_inner_top', 'homedecor:shingle_inner_corner_', '_technic_cnc_slope_inner_edge', 1 ); - - -- actually, that would be homedecor.detail, but we don't want to exaggerate; 16 certainly is enough - - local c_snow_stair = minetest.get_content_id( 'moresnow:snow_stair_top' ); - local c_snow_slab = minetest.get_content_id( 'moresnow:snow_slab_top' ); - local c_snow_top = minetest.get_content_id( 'moresnow:snow_top' ); - local c_snow = minetest.get_content_id( 'default:snow' ); - local c_snow_outer_stair = minetest.get_content_id( 'moresnow:snow_outer_stair_top' ); - local c_snow_inner_stair = minetest.get_content_id( 'moresnow:snow_inner_stair_top' ); - - for n,v in pairs( minetest.registered_nodes ) do - - local id = minetest.get_content_id( n ); - - if( not( id ) or moresnow.snow_cover[ id ] ) then - - -- do nothing; the node has been dealt with - - elseif( n and minetest.registered_nodes[ n ] - and minetest.registered_nodes[ n ].drop - and minetest.registered_nodes[ n ].drop == 'default:snow' ) then - - -- no snow on snow - - - elseif( v and v.drawtype and v.drawtype == 'nodebox' and v.node_box - and v.node_box.type and v.node_box.type=='fixed' - and v.node_box.fixed ) then - - local nb = v.node_box.fixed; - - -- might be a slab (or something which has a sufficiently similar surface compared to a slab) - if( ( #nb == 1 - and math.max( nb[1][2], nb[1][5])==0 - and math.abs( nb[1][4] - nb[1][1] ) >= 0.9 - and math.abs( nb[1][6] - nb[1][3] ) >= 0.9 ) - - or ( type( nb[1] )~='table' - and #nb == 6 - and math.max( nb[2], nb[5] )==0 - and math.abs( nb[4]-nb[1] ) >= 0.9 - and math.abs( nb[6]-nb[3] ) >= 0.9 )) then - - moresnow.snow_cover[ id ] = c_snow_slab; - - -- might be a stair - elseif( #nb == 2 ) then - local c = { math.min( nb[1][1], nb[1][4] ), math.min( nb[1][2], nb[1][5] ), math.min( nb[1][3], nb[1][4] ), - math.max( nb[1][1], nb[1][4] ), math.max( nb[1][2], nb[1][5] ), math.max( nb[1][3], nb[1][4] ), - math.min( nb[2][1], nb[2][4] ), math.min( nb[2][2], nb[2][5] ), math.min( nb[2][3], nb[2][4] ), - math.max( nb[2][1], nb[2][4] ), math.max( nb[2][2], nb[2][5] ), math.max( nb[2][3], nb[2][4] ) }; - - if( (( c[ 5]==0 and c[11]==0.5) - or ( c[ 5]==0.5 and c[11]==0 )) - and math.abs( c[ 4]-c[1]) >= 0.9 - and math.abs( c[10]-c[7]) >= 0.9 ) then - - moresnow.snow_cover[ id ] = c_snow_stair; - - -- moreblocks _outer: - elseif( nb[1][1]==-0.5 and nb[1][2]==-0.5 and nb[1][3]==-0.5 - and nb[1][4]== 0.5 and nb[1][5]== 0 and nb[1][6]== 0.5 - and nb[2][1]==-0.5 and nb[2][2]== 0 and nb[2][3]== 0 - and nb[2][4]== 0 and nb[2][5]== 0.5 and nb[2][6]== 0.5 ) then - - moresnow.snow_cover[ id ] = c_snow_outer_stair; - else - moresnow.snow_cover[ id ] = c_snow_top; - end - - -- moreblocks _inner: - elseif( #nb==3 - and nb[1][1]==-0.5 and nb[1][2]==-0.5 and nb[1][3]==-0.5 - and nb[1][4]== 0.5 and nb[1][5]== 0 and nb[1][6]== 0.5 - - and nb[2][1]==-0.5 and nb[2][2]== 0 and nb[2][3]== 0 - and nb[2][4]== 0.5 and nb[2][5]== 0.5 and nb[2][6]== 0.5 - - and nb[3][1]==-0.5 and nb[3][2]== 0 and nb[3][3]==-0.5 - and nb[3][4]== 0 and nb[3][5]== 0.5 and nb[3][6]== 0 ) then - - moresnow.snow_cover[ id ] = c_snow_inner_stair; - else - moresnow.snow_cover[ id ] = c_snow_top; - end - - -- add snow to the bottom of the node below; it will look acceptable, provided there is a solid node below - elseif( v and v.drawtype - and ( v.drawtype == 'fencelike' or v.drawtype=='plantlike' - or v.drawtype == 'signlike' or v.drawtype=='torchlike' )) then - - moresnow.snow_cover[ id ] = c_snow_top; - - -- nodes where a snow cover would not fit (rails for example would get invisible) - elseif( v and v.drawtype - and ( v.drawtype == 'airlike' or v.drawtype=='liquid' - or v.drawtype == 'raillike' or v.drawtype=='flowingliquid' )) then - - moresnow.snow_cover[ id ] = c_air; - else - moresnow.snow_cover[ id ] = c_snow; - end - end -end - --- search for stairs and slabs after all nodes have been generated -minetest.after( 0, moresnow.identify_stairs_and_slabs ); - +-- 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'); +-- takes a look at all defined nodes after startup and stores which shape they are; +-- 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'); diff --git a/snow_analyze_shapes.lua b/snow_analyze_shapes.lua new file mode 100644 index 0000000..ca1a18b --- /dev/null +++ b/snow_analyze_shapes.lua @@ -0,0 +1,161 @@ + +-- find out which nodes are stairs and which are slabs (those are handled diffrently by our snow here); +-- this is necessary in order to determine which shape the snow on top of the node will take +-- (of course this only works for a few shapes and does not even take rotation into consideration) +moresnow.snow_cover = {}; + +-- homedecor and technic did not settle on common param2 interpretation :-( +moresnow.snow_param2_offset = {}; + +-- homedecor 3d shingles and technic cnc items are handled here +moresnow.identify_special_slopes = function( new_name, homedecor_prefix, technic_postfix, param2_offset ) + -- these nodes are only supported if homedecor and/or technic are installed + local c_new_snow_node = minetest.get_content_id( new_name ); + if( not( c_new_snow_node )) then + return; + end + + local c_ignore = minetest.get_content_id( 'ignore' ); + + local homedecor_materials = {'terracotta','wood','asphalt'}; + local technic_materials = {'dirt','wood','stone','cobble','brick','sandstone','leaves', + 'tree','steelblock','bronzeblock','stainless_steel','marble','granite'}; + + for _,v in ipairs( homedecor_materials ) do + local id = minetest.get_content_id( homedecor_prefix..v ); + -- the node has to be registered at this point; thus, the soft-dependency on homedecor and technic + if( id and id ~= c_ignore ) then + moresnow.snow_cover[ id ] = c_new_snow_node; + end + end + for _,v in ipairs( technic_materials ) do + local prefix = 'default:'; + if( v=='stainless_steel' or v=='marble' or v=='granite' ) then + prefix = 'technic:'; + end + + local id = minetest.get_content_id( prefix..v..technic_postfix ); + -- the node has to be registered at this point; thus, the soft-dependency on homedecor and technic + if( id and id ~= c_ignore ) then + moresnow.snow_cover[ id ] = c_new_snow_node; + -- homedecor and technic use diffrent param2 for the same shape + if( param2_offset ) then + moresnow.snow_param2_offset[ id ] = param2_offset; + end + end + end +end + +-- identify stairs and slabs (roughly!) by their nodeboxes +moresnow.identify_stairs_and_slabs = function() + + moresnow.identify_special_slopes( 'moresnow:snow_ramp_top', 'homedecor:shingle_side_', '_technic_cnc_slope', 0 ); + moresnow.identify_special_slopes( 'moresnow:snow_ramp_outer_top', 'homedecor:shingle_outer_corner_', '_technic_cnc_slope_edge', 1 ); + moresnow.identify_special_slopes( 'moresnow:snow_ramp_inner_top', 'homedecor:shingle_inner_corner_', '_technic_cnc_slope_inner_edge', 1 ); + + -- actually, that would be homedecor.detail, but we don't want to exaggerate; 16 certainly is enough + + local c_snow_stair = minetest.get_content_id( 'moresnow:snow_stair_top' ); + local c_snow_slab = minetest.get_content_id( 'moresnow:snow_slab_top' ); + local c_snow_top = minetest.get_content_id( 'moresnow:snow_top' ); + local c_snow = minetest.get_content_id( 'default:snow' ); + local c_snow_outer_stair = minetest.get_content_id( 'moresnow:snow_outer_stair_top' ); + local c_snow_inner_stair = minetest.get_content_id( 'moresnow:snow_inner_stair_top' ); + + for n,v in pairs( minetest.registered_nodes ) do + + local id = minetest.get_content_id( n ); + + if( not( id ) or moresnow.snow_cover[ id ] ) then + + -- do nothing; the node has been dealt with + + elseif( n and minetest.registered_nodes[ n ] + and minetest.registered_nodes[ n ].drop + and minetest.registered_nodes[ n ].drop == 'default:snow' ) then + + -- no snow on snow + + + elseif( v and v.drawtype and v.drawtype == 'nodebox' and v.node_box + and v.node_box.type and v.node_box.type=='fixed' + and v.node_box.fixed ) then + + local nb = v.node_box.fixed; + + -- might be a slab (or something which has a sufficiently similar surface compared to a slab) + if( ( #nb == 1 + and math.max( nb[1][2], nb[1][5])==0 + and math.abs( nb[1][4] - nb[1][1] ) >= 0.9 + and math.abs( nb[1][6] - nb[1][3] ) >= 0.9 ) + + or ( type( nb[1] )~='table' + and #nb == 6 + and math.max( nb[2], nb[5] )==0 + and math.abs( nb[4]-nb[1] ) >= 0.9 + and math.abs( nb[6]-nb[3] ) >= 0.9 )) then + + moresnow.snow_cover[ id ] = c_snow_slab; + + -- might be a stair + elseif( #nb == 2 ) then + local c = { math.min( nb[1][1], nb[1][4] ), math.min( nb[1][2], nb[1][5] ), math.min( nb[1][3], nb[1][4] ), + math.max( nb[1][1], nb[1][4] ), math.max( nb[1][2], nb[1][5] ), math.max( nb[1][3], nb[1][4] ), + math.min( nb[2][1], nb[2][4] ), math.min( nb[2][2], nb[2][5] ), math.min( nb[2][3], nb[2][4] ), + math.max( nb[2][1], nb[2][4] ), math.max( nb[2][2], nb[2][5] ), math.max( nb[2][3], nb[2][4] ) }; + + if( (( c[ 5]==0 and c[11]==0.5) + or ( c[ 5]==0.5 and c[11]==0 )) + and math.abs( c[ 4]-c[1]) >= 0.9 + and math.abs( c[10]-c[7]) >= 0.9 ) then + + moresnow.snow_cover[ id ] = c_snow_stair; + + -- moreblocks _outer: + elseif( nb[1][1]==-0.5 and nb[1][2]==-0.5 and nb[1][3]==-0.5 + and nb[1][4]== 0.5 and nb[1][5]== 0 and nb[1][6]== 0.5 + and nb[2][1]==-0.5 and nb[2][2]== 0 and nb[2][3]== 0 + and nb[2][4]== 0 and nb[2][5]== 0.5 and nb[2][6]== 0.5 ) then + + moresnow.snow_cover[ id ] = c_snow_outer_stair; + else + moresnow.snow_cover[ id ] = c_snow_top; + end + + -- moreblocks _inner: + elseif( #nb==3 + and nb[1][1]==-0.5 and nb[1][2]==-0.5 and nb[1][3]==-0.5 + and nb[1][4]== 0.5 and nb[1][5]== 0 and nb[1][6]== 0.5 + + and nb[2][1]==-0.5 and nb[2][2]== 0 and nb[2][3]== 0 + and nb[2][4]== 0.5 and nb[2][5]== 0.5 and nb[2][6]== 0.5 + + and nb[3][1]==-0.5 and nb[3][2]== 0 and nb[3][3]==-0.5 + and nb[3][4]== 0 and nb[3][5]== 0.5 and nb[3][6]== 0 ) then + + moresnow.snow_cover[ id ] = c_snow_inner_stair; + else + moresnow.snow_cover[ id ] = c_snow_top; + end + + -- add snow to the bottom of the node below; it will look acceptable, provided there is a solid node below + elseif( v and v.drawtype + and ( v.drawtype == 'fencelike' or v.drawtype=='plantlike' + or v.drawtype == 'signlike' or v.drawtype=='torchlike' )) then + + moresnow.snow_cover[ id ] = c_snow_top; + + -- nodes where a snow cover would not fit (rails for example would get invisible) + elseif( v and v.drawtype + and ( v.drawtype == 'airlike' or v.drawtype=='liquid' + or v.drawtype == 'raillike' or v.drawtype=='flowingliquid' )) then + + moresnow.snow_cover[ id ] = c_air; + else + moresnow.snow_cover[ id ] = c_snow; + end + end +end + +-- search for stairs and slabs after all nodes have been generated +minetest.after( 0, moresnow.identify_stairs_and_slabs ); diff --git a/snow_cover_nodes.lua b/snow_cover_nodes.lua new file mode 100644 index 0000000..e3961ff --- /dev/null +++ b/snow_cover_nodes.lua @@ -0,0 +1,106 @@ + + +-- 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, { + description = "Snow", + tiles = {"default_snow.png"}, +-- tiles = {"moreautumn.png"}, + inventory_image = "default_snowball.png", + wield_image = "default_snowball.png", + is_ground_content = true, + paramtype = "light", + paramtype2 = "facedir", + buildable_to = true, + drawtype = "nodebox", + freezemelt = "default:water_flowing", + node_box = { + -- leveled would not work well in this situation + type = "fixed", + fixed = fixed_nodebox, + }, + drop = "default:snow", + groups = {crumbly=3,falling_node=1, melts=1, float=1, not_in_creative_inventory=1}, + sounds = default.node_sound_dirt_defaults({ + footstep = {name="default_snow_footstep", gain=0.25}, + dug = {name="default_snow_footstep", gain=0.75}, + }), + on_construct = moresnow.on_construct, + }) +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; + +-- 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", { + {-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", { + {-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}, + + {-0.5, -1.0+2/16, 0-1/32, 0, -0.5, 0 }, + {-0.5, -1.5, -0.5-1/32, 0.5, -1.0, -0.5}, + + {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", { + { 0, -1.0, -0.5, 0.5, -1.0+2/16, 0 }, + + { 0, -0.5, 0, 0.5, -0.5+2/16, 0.5}, + {-0.5, -0.5, -0.5, 0, -0.5+2/16, 0.5}, + + { 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}, + }); + + +moresnow.register_shape = function( shape, new_name ) + + local detail = 16; + + local slopeboxedge = {}; + for i = 0, detail-1 do + + if( shape==1 ) then -- slope; normal roof shingles + slopeboxedge[i+1]={ -0.5, (i/detail)-1.5+(1.25/detail), (i/detail)-0.5, + 0.5, (i/detail)-1.5+(1.25/detail)+(1/detail), (i/detail)-0.5+(1/detail)}; + + elseif( shape==2 ) then -- outer corner + slopeboxedge[i+1]={ -0.5, (i/detail)-1.5+(1.25/detail), (i/detail)-0.5, + 0.5-(i/detail), (i/detail)-1.5+(1.25/detail)+(1/detail), (i/detail)-0.5+(1/detail)}; + + slopeboxedge[i+detail*1]={ 0.5-(i/detail), (i/detail)-1.5+(1.25/detail)-(1/detail), 0.5, + 0.5-(i/detail)+(1/detail), (i/detail)-1.5+(1.25/detail), -0.5+(i/detail) }; + + + elseif( shape==3 ) then -- inner corner + local v = detail-i; + slopeboxedge[i+1]={ (i/detail)-0.5, (v/detail)-1.5+(1.25/detail)-(1/detail), -0.5+(1/detail-(1/detail)), + (i/detail)-0.5+(1/detail), (v/detail)-1.5+(1.25/detail), 0.5-(i/detail) }; + + slopeboxedge[i+detail*1]={ 0.5, (v/detail)-1.5+(1.25/detail), 0.5-(i/detail), + -0.5+(i/detail), (v/detail)-1.5+(1.25/detail)+(1/detail), 0.5-(i/detail)+(1/detail) }; + end + end + + moresnow.register_snow_top( new_name, slopeboxedge ); +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'); +end + diff --git a/snow_on_construct.lua b/snow_on_construct.lua new file mode 100644 index 0000000..de15605 --- /dev/null +++ b/snow_on_construct.lua @@ -0,0 +1,161 @@ + +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 + + suggested = minetest.get_name_from_content_id( suggested ); + + -- no rule for this node + if( not( suggested )) then + return; + end + + 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 + + -- 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'; + 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 + end + end +end +