moresnow/snow_on_construct.lua

251 lines
7.8 KiB
Lua

moresnow.translation_table = {}
moresnow.build_translation_table = function()
local shapes = {'top', 'fence_top', 'stair_top', 'slab_top',
'panel_top', 'micro_top', 'outer_stair_top', 'inner_stair_top',
'ramp_top', 'ramp_outer_top', 'ramp_inner_top' };
for _,t in ipairs(moresnow.nodetypes) do
moresnow.translation_table[ t ] = {};
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
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 )
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
moresnow.on_construct_wool = function( pos, falling_node_name, color )
if( not( falling_node_name )) then
falling_node_name = 'moresnow:wool_'..color;
end
local res = moresnow.on_construct( pos, falling_node_name, 'moresnow:wool_'..color, 'wool_'..color );
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 <= 24 ) then
suggested = moresnow.c_snow;
-- else it's a slab
end
elseif( suggested == moresnow.c_snow_panel ) then
-- vertical panel (mostly); can't be handled well; therefore, treat as a nodebox
if( p2 >= 4 and p2 <= 24 ) then
suggested = moresnow.c_snow_top;
end
elseif( suggested == moresnow.c_snow_micro ) then
-- microblocks in diffrent positions from the normal ones are too difficult
if( p2 >= 4 and p2 <= 24 ) then
suggested = moresnow.c_snow_top;
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 <= 24 ) 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 <= 24 ) then
suggested = moresnow.c_snow;
end
end
-- c_snow_top does not have facedir
if( suggested == moresnow.c_snow_top ) then
p2 = 1;
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
if( not( minetest.registered_nodes[ default_name ] ) or default_name=='ignore') then
return;
end
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
if( not( minetest.registered_nodes[ suggested ] ) or suggested=='ignore') then
return;
end
return { name = suggested, param2 = res.param2};
end
end