2015-05-01 18:04:03 +02:00
handle_schematics.get_content_id_replaced = function ( node_name , replacements )
2019-10-25 14:54:06 +02:00
if ( not ( node_name ) ) then
2015-05-01 18:04:03 +02:00
return minetest.get_content_id ( ' ignore ' ) ;
end
2019-11-11 19:10:16 +01:00
local new_name = node_name
2019-10-25 14:54:06 +02:00
if ( replacements and replacements.table and replacements.table [ node_name ] ) then
2019-11-11 19:10:16 +01:00
new_name = replacements.table [ node_name ] ;
2015-05-01 18:04:03 +02:00
end
2019-11-11 19:10:16 +01:00
if ( minetest.registered_aliases [ new_name ] ) then
new_name = minetest.registered_aliases [ new_name ]
end
-- try the original name if the new one doesn't exist
if ( not ( minetest.registered_nodes [ new_name ] )
and minetest.registered_nodes [ node_name ] ) then
new_name = node_name
end
return minetest.get_content_id ( new_name ) ;
2015-05-01 18:04:03 +02:00
end
-- either uses get_node_or_nil(..) or the data from voxelmanip
-- the function might as well be local (only used by *.mg_drop_moresnow)
handle_schematics.get_node_somehow = function ( x , y , z , a , data , param2_data )
if ( a and data and param2_data ) then
return { content = data [ a : index ( x , y , z ) ] , param2 = param2_data [ a : index ( x , y , z ) ] } ;
end
-- no voxelmanip; get the node the normal way
local node = minetest.get_node_or_nil ( { x = x , y = y , z = z } ) ;
if ( not ( node ) ) then
return { content = moresnow.c_ignore , param2 = 0 } ;
end
return { content = minetest.get_content_id ( node.name ) , param2 = node.param2 , name = node.name } ;
end
-- "drop" moresnow snow on diffrent shapes; works for voxelmanip and node-based setting
2017-06-26 23:26:36 +02:00
handle_schematics.mg_drop_moresnow = function ( x , z , y_top , y_bottom , a , data , param2_data , cid )
2015-05-01 18:04:03 +02:00
-- this only works if moresnow is installed
if ( not ( handle_schematics.moresnow_installed ) ) then
return ;
end
local y = y_top ;
local node_above = handle_schematics.get_node_somehow ( x , y + 1 , z , a , data , param2_data ) ;
local node_below = nil ;
while ( y >= y_bottom ) do
node_below = handle_schematics.get_node_somehow ( x , y , z , a , data , param2_data ) ;
if ( node_above.content == moresnow.c_air
and node_below.content
and node_below.content ~= moresnow.c_ignore
and node_below.content ~= moresnow.c_air ) then
-- turn water into ice, but don't drop snow on it
2017-06-26 23:26:36 +02:00
if ( node_below.content == cid.c_water_source
or node_below.content == cid.c_river_water_source ) then
return { height = y , suggested = { new_id = cid.c_ice , param2 = 0 } } ;
2015-05-01 18:04:03 +02:00
end
-- if the node below drops snow when digged (i.e. is either snow or a moresnow node), we're finished
local get_drop = minetest.get_name_from_content_id ( node_below.content ) ;
if ( get_drop ) then
2017-06-26 23:26:36 +02:00
get_drop = handle_schematics.node_defined ( get_drop ) ;
2015-05-01 18:04:03 +02:00
if ( get_drop and get_drop.drop and type ( get_drop.drop ) == ' string ' and get_drop.drop == ' default:snow ' ) then
return ;
end
end
if ( not ( node_below.content )
or node_below.content == moresnow.c_snow ) then
return ;
end
local suggested = moresnow.suggest_snow_type ( node_below.content , node_below.param2 ) ;
-- c_snow_top and c_snow_fence can only exist when the node 2 below is a solid one
if ( suggested.new_id == moresnow.c_snow_top
or suggested.new_id == moresnow.c_snow_fence ) then
local node_below2 = handle_schematics.get_node_somehow ( x , y - 1 , z , a , data , param2_data ) ;
if ( node_below2.content ~= moresnow.c_ignore
and node_below2.content ~= moresnow.c_air ) then
local suggested2 = moresnow.suggest_snow_type ( node_below2.content , node_below2.param2 ) ;
if ( suggested2.new_id == moresnow.c_snow ) then
return { height = y + 1 , suggested = suggested } ;
end
end
-- it is possible that this is not the right shape; if so, the snow will continue to fall down
elseif ( suggested.new_id ~= moresnow.c_ignore ) then
return { height = y + 1 , suggested = suggested } ;
end
-- TODO return; -- abort; there is no fitting moresnow shape for the node below
end
y = y - 1 ;
node_above = node_below ;
end
end
-- helper function for generate_building
-- places a marker that allows players to buy plots with houses on them (in order to modify the buildings)
local function generate_building_plotmarker ( pos , minp , maxp , data , param2_data , a , cid , building_nr_in_bpos , village_id , filename )
-- position the plot marker so that players can later buy this plot + building in order to modify it
-- pos.o contains the original orientation (determined by the road and the side the building is
local p = { x = pos.x , y = pos.y + 1 , z = pos.z } ;
2017-06-27 04:11:37 +02:00
-- vector for placing mg_villages:mob_spawner
local v = { x = 0 , z = 0 } ;
2015-05-01 18:04:03 +02:00
if ( pos.o == 0 ) then
p.x = p.x - 1 ;
p.z = p.z + pos.bsizez - 1 ;
2017-06-27 04:11:37 +02:00
v.z = - 1 ;
2017-06-27 16:11:52 +02:00
p.yaw = 90 ;
2015-05-01 18:04:03 +02:00
elseif ( pos.o == 2 ) then
p.x = p.x + pos.bsizex ;
2017-06-27 04:11:37 +02:00
v.z = 1 ;
2017-06-27 16:11:52 +02:00
p.yaw = 270 ;
2015-05-01 18:04:03 +02:00
elseif ( pos.o == 1 ) then
p.z = p.z + pos.bsizez ;
p.x = p.x + pos.bsizex - 1 ;
2017-06-27 04:11:37 +02:00
v.x = - 1 ;
2017-06-27 16:11:52 +02:00
p.yaw = 0 ;
2015-05-01 18:04:03 +02:00
elseif ( pos.o == 3 ) then
p.z = p.z - 1 ;
2017-06-27 04:11:37 +02:00
v.x = 1 ;
2017-06-27 16:11:52 +02:00
p.yaw = 180 ;
2015-05-01 18:04:03 +02:00
end
-- actually position the marker
if ( p.x >= minp.x and p.x <= maxp.x and p.z >= minp.z and p.z <= maxp.z and p.y >= minp.y and p.y <= maxp.y ) then
2015-08-12 17:37:46 +02:00
if ( handle_schematics.moresnow_installed
and data [ a : index ( p.x , p.y , p.z ) ] == cid.c_snow
and p.y < maxp.y
and moresnow and moresnow.c_snow_top and cid.c_snow_top ~= cid.c_ignore ) then
2015-05-01 18:04:03 +02:00
data [ a : index ( p.x , p.y + 1 , p.z ) ] = moresnow.c_snow_top ;
end
data [ a : index ( p.x , p.y , p.z ) ] = cid.c_plotmarker ;
param2_data [ a : index ( p.x , p.y , p.z ) ] = pos.brotate ;
-- store the necessary information in the marker so that it knows for which building it is responsible
local meta = minetest.get_meta ( p ) ;
meta : set_string ( ' village_id ' , village_id ) ;
meta : set_int ( ' plot_nr ' , building_nr_in_bpos ) ;
meta : set_string ( ' infotext ' , ' Plot No. ' .. tostring ( building_nr_in_bpos ) .. ' with ' .. tostring ( filename ) ) ;
2017-06-27 16:11:52 +02:00
-- information about the direction the mob ought to look at
meta : set_int ( ' yaw ' , p.yaw ) ;
2015-05-01 18:04:03 +02:00
end
2017-06-27 04:11:37 +02:00
-- place a mob spawner in front of the house for each bed
-- we do it here so that the roads will not overwrite it
local binfo = mg_villages.BUILDINGS [ pos.btype ] ;
2017-06-27 04:15:39 +02:00
if ( not ( binfo ) or not ( binfo.bed_count ) or binfo.bed_count < 1 or not ( minetest.registered_nodes [ " mg_villages:mob_spawner " ] ) ) then
2017-06-27 04:11:37 +02:00
return ;
end
cid.c_mob_spawner = minetest.get_content_id ( " mg_villages:mob_spawner " ) ;
2017-07-29 22:24:25 +02:00
p.y = p.y - 2 ; -- hide the spawner from view
2017-06-27 04:11:37 +02:00
for i = 1 , binfo.bed_count do
p.x = p.x + v.x ;
p.z = p.z + v.z ;
if ( p.x >= minp.x and p.x <= maxp.x and p.z >= minp.z
and p.z <= maxp.z and p.y >= minp.y and p.y <= maxp.y ) then
-- place the mob spawner
data [ a : index ( p.x , p.y , p.z ) ] = cid.c_mob_spawner ;
-- not really necessary but can't hurt
param2_data [ a : index ( p.x , p.y , p.z ) ] = pos.brotate ;
-- store where to find information about the mob this spawner is responsible for
local meta = minetest.get_meta ( p ) ;
meta : set_string ( ' village_id ' , village_id ) ;
meta : set_int ( ' plot_nr ' , building_nr_in_bpos ) ;
meta : set_int ( ' bed_nr ' , i ) ;
meta : set_string ( ' infotext ' , ' MOB SPAWNER for bed nr ' .. tostring ( i ) .. ' on plot nr ' .. tostring ( building_nr_in_bpos ) .. ' in village ' .. tostring ( village_id ) ) ;
end
end
2015-05-01 18:04:03 +02:00
end
2017-06-13 02:10:46 +02:00
-- pos has to contain information about the building - o (orientation), bsizex and bsizez
-- this function returns a position in front of the building, with the building stretching equally to the right and left
-- (useful for mobs who want to leave/enter the plot)
2017-06-18 20:34:19 +02:00
-- bed_nr can be used to assign diffrent spawn points to mobs in diffrent beds
handle_schematics.get_pos_in_front_of_house = function ( pos , bed_nr )
2017-06-20 19:39:19 +02:00
if ( not ( bed_nr ) ) then
bed_nr = 0 ;
2017-06-18 20:34:19 +02:00
end
2017-06-20 20:12:23 +02:00
local p = { x = pos.x , y = pos.y + 1 , z = pos.z , yaw = 0 } ;
2017-06-13 02:10:46 +02:00
if ( pos.o == 0 ) then
p.x = p.x - 1 ;
2017-06-26 23:26:36 +02:00
p.z = p.z + pos.bsizez - 1 - bed_nr ;
-- p.z = p.z - math.floor(pos.bsizex/2+0.5) - bed_nr;
2017-06-20 20:12:23 +02:00
p.yaw = 90 ;
2017-06-13 02:10:46 +02:00
elseif ( pos.o == 2 ) then
p.x = p.x + pos.bsizex ;
2017-06-26 23:26:36 +02:00
-- p.z = p.z + math.floor(pos.bsizex/2+0.5) + bed_nr;
p.z = p.z + bed_nr ;
2017-06-20 20:12:23 +02:00
p.yaw = 270 ;
2017-06-13 02:10:46 +02:00
elseif ( pos.o == 1 ) then
p.z = p.z + pos.bsizez ;
2017-06-26 23:26:36 +02:00
p.x = p.x + pos.bsizex - 1 - bed_nr ;
-- p.x = p.x - math.floor(pos.bsizez/2+0.5) - bed_nr;
2017-06-20 20:12:23 +02:00
p.yaw = 0 ;
2017-06-13 02:10:46 +02:00
elseif ( pos.o == 3 ) then
p.z = p.z - 1 ;
2017-06-26 23:26:36 +02:00
-- p.x = p.x + math.floor(pos.bsizez/2+0.5) + bed_nr;
p.x = p.x + bed_nr ;
2017-06-20 20:12:23 +02:00
p.yaw = 180 ;
2017-06-13 02:10:46 +02:00
end
return p ;
end
2015-05-01 18:04:03 +02:00
-- we do have a list of all nodenames the building contains (the .mts file provided it);
-- we can thus apply all replacements to these nodenames;
-- this also checks param2 and sets some other variables to indicate that it's i.e. a tree or a chest
-- (which both need special handling later on)
local function generate_building_translate_nodenames ( nodenames , replacements , cid , binfo_scm , mirror_x , mirror_z )
if ( not ( nodenames ) ) then
return ;
end
local i ;
local v ;
local new_nodes = { } ;
for i , node_name in ipairs ( nodenames ) do
new_nodes [ i ] = { } ; -- array for collecting information about the new content id for nodes with number "i" in their .mts savefile
-- some nodes may be called differently when mirrored; needed for doors
local new_node_name = node_name ;
if ( new_node_name and ( mirror_x or mirror_z ) and handle_schematics.mirrored_node [ new_node_name ] ) then
new_node_name = handle_schematics.mirrored_node [ node_name ] ;
new_nodes [ i ] . is_mirrored = 1 ; -- currently unused
end
-- apply the replacements
if ( new_node_name and replacements.table [ new_node_name ] ) then
new_node_name = replacements.table [ new_node_name ] ;
new_nodes [ i ] . is_replaced = 1 ; -- currently unused
end
2015-05-03 23:11:17 +02:00
-- those chests do not exist as regular nodes; they're just placeholders
if ( node_name == ' cottages:chest_private '
or node_name == ' cottages:chest_work '
or node_name == ' cottages:chest_storage ' ) then
new_nodes [ i ] . is_replaced = 1 ; -- currently unused
new_nodes [ i ] . special_chest = node_name ;
-- TODO: perhaps use a locked chest owned by the mob living there?
-- place a normal chest here
new_nodes [ i ] . new_content = cid.c_chest ;
new_nodes [ i ] . special_chest = node_name ;
new_node_name = ' default:chest ' ;
elseif ( new_node_name == ' cottages:chest_private '
or new_node_name == ' cottages:chest_work '
or new_node_name == ' cottages:chest_storage ' ) then
new_nodes [ i ] . is_replaced = 1 ; -- currently unused
new_nodes [ i ] . special_chest = new_node_name ;
-- TODO: perhaps use a locked chest owned by the mob living there?
-- place a normal chest here
new_nodes [ i ] . new_content = cid.c_chest ;
2017-02-16 05:47:38 +01:00
elseif ( node_name == ' default:chest '
or new_node_name == ' default:chest ' ) then
new_nodes [ i ] . is_replaced = 1 ; -- currently unused
2017-02-25 19:44:30 +01:00
new_nodes [ i ] . special_chest = ' default:chest ' ;
2017-02-16 05:47:38 +01:00
new_nodes [ i ] . new_content = cid.c_chest ;
2017-02-25 19:44:30 +01:00
elseif ( node_name == ' default:bookshelf '
or new_node_name == ' default:bookshelf ' ) then
new_nodes [ i ] . is_replaced = 1 ; -- currently unused
new_nodes [ i ] . special_chest = ' default:bookshelf ' ;
new_nodes [ i ] . new_content = cid.c_bookshelf ;
2017-06-05 14:47:15 +02:00
-- recognize beds
elseif ( handle_schematics.bed_node_names [ node_name ]
or handle_schematics.bed_node_names [ new_node_name ] ) then
new_nodes [ i ] . is_bed = 1 ;
2017-07-20 05:47:55 +02:00
elseif ( node_name == " mg_villages:mob_workplace_marker "
or new_node_name == " mg_villages:mob_workplace_marker " ) then
new_nodes [ i ] . is_workplace_marker = 1 ;
2015-05-03 23:11:17 +02:00
end
2015-05-01 18:04:03 +02:00
-- only existing nodes can be placed
2017-06-26 23:26:36 +02:00
local regnode = handle_schematics.node_defined ( new_node_name ) ;
if ( new_node_name and regnode ) then
-- apply global replacements
if ( handle_schematics.global_replacement_table [ new_node_name ] ) then
new_node_name = handle_schematics.global_replacement_table [ new_node_name ] ;
end
2015-05-01 18:04:03 +02:00
new_nodes [ i ] . new_node_name = new_node_name ;
new_nodes [ i ] . new_content = minetest.get_content_id ( new_node_name ) ;
if ( regnode.on_construct ) then
new_nodes [ i ] . on_construct = 1 ;
end
local new_content = new_nodes [ i ] . new_content ;
2017-05-08 21:28:14 +02:00
if ( new_content == cid.c_dirt_with_grass ) then
2015-05-01 18:04:03 +02:00
new_nodes [ i ] . is_grass = 1 ;
2017-05-08 21:28:14 +02:00
-- dirt acts as a general placeholder
elseif ( new_content == cid.c_dirt ) then
new_nodes [ i ] . is_dirt = 1 ;
2015-05-01 18:04:03 +02:00
elseif ( new_content == cid.c_sapling
or new_content == cid.c_jsapling
or new_content == cid.c_psapling
2017-07-03 19:43:28 +02:00
or new_content == cid.c_asapling
or new_content == cid.c_aspsapling
2015-05-01 18:04:03 +02:00
or new_content == cid.c_savannasapling
or new_content == cid.c_pinesapling ) then
-- store that a tree is to be grown there
new_nodes [ i ] . is_tree = 1 ;
elseif ( new_content == cid.c_chest
2017-02-25 19:44:30 +01:00
or new_content == cid.c_bookshelf
2015-05-01 18:04:03 +02:00
or new_content == cid.c_chest_locked
or new_content == cid.c_chest_shelf
or new_content == cid.c_chest_ash
or new_content == cid.c_chest_aspen
or new_content == cid.c_chest_birch
or new_content == cid.c_chest_maple
or new_content == cid.c_chest_chestnut
or new_content == cid.c_chest_pine
or new_content == cid.c_chest_spruce ) then
-- we're dealing with a chest that might need filling
new_nodes [ i ] . is_chestlike = 1 ;
elseif ( new_content == cid.c_sign ) then
-- the sign may require some text to be written on it
new_nodes [ i ] . is_sign = 1 ;
2016-03-20 23:57:53 +01:00
-- doors need special treatment as they changed from 2 to 1 node
elseif ( string.sub ( node_name , 1 , 6 ) == " doors: "
and string.sub ( new_node_name , 1 , 6 ) == " doors: " ) then
if ( string.sub ( new_node_name , - 2 ) == " _a " ) then
new_nodes [ i ] . is_door_a = 1 ;
elseif ( string.sub ( new_node_name , - 2 ) == " _b " ) then
new_nodes [ i ] . is_door_b = 1 ;
end
2017-02-10 01:17:04 +01:00
-- if we are placing a glass node, param2 needs to be set to 0
elseif ( regnode and regnode.drawtype
and ( regnode.drawtype == " glasslike " or regnode.drawtype == " glasslike_framed " or regnode.drawtype == " glasslike_framed_optional " ) ) then
2017-02-10 01:26:16 +01:00
new_nodes [ i ] . set_param2_to_0 = 1 ;
-- torches can be 3d now; for that, they use diffrent nodes
elseif ( new_node_name == ' mg_villages:torch ' or new_node_name == ' default:torch ' ) then
new_nodes [ i ] . is_torch = 1 ;
2015-05-01 18:04:03 +02:00
end
-- handle_schematics.get_param2_rotated( 'facedir', param2 ) needs to be called for nodes
-- which use either facedir or wallmounted;
-- realtest rotates some nodes diffrently and does not come with default:ladder
2017-06-26 23:26:36 +02:00
if ( node_name == ' default:ladder ' and handle_schematics.is_realtest ) then
2015-05-01 18:04:03 +02:00
new_nodes [ i ] . change_param2 = { } ; --{ 2->1, 5->2, 3->3, 4->0 }
new_nodes [ i ] . change_param2 [ 2 ] = 1 ;
new_nodes [ i ] . change_param2 [ 5 ] = 2 ;
new_nodes [ i ] . change_param2 [ 3 ] = 3 ;
new_nodes [ i ] . change_param2 [ 4 ] = 0 ;
new_nodes [ i ] . paramtype2 = ' facedir ' ;
-- ..except if they are stairs or ladders
elseif ( string.sub ( node_name , 1 , 7 ) == ' stairs: ' or string.sub ( node_name , 1 , 6 ) == ' doors: ' ) then
new_nodes [ i ] . paramtype2 = ' facedir ' ;
-- normal nodes
elseif ( regnode and regnode.paramtype2 and ( regnode.paramtype2 == ' facedir ' or regnode.paramtype2 == ' wallmounted ' ) ) then
new_nodes [ i ] . paramtype2 = regnode.paramtype2 ;
end
-- we tried our best, but the replacement node is not defined
elseif ( new_node_name ~= ' mg:ignore ' ) then
local msg = ' ERROR: Did not find a suitable replacement for ' .. tostring ( node_name ) .. ' (suggested but inexistant: ' ..
tostring ( new_node_name ) .. ' ). Building: ' .. tostring ( binfo_scm ) .. ' . ' ;
if ( mg_villages and mg_villages.print ) then
mg_villages.print ( mg_villages.DEBUG_LEVEL_WARNING , msg ) ;
else
print ( msg ) ;
end
msg = nil ;
new_nodes [ i ] . ignore = 1 ; -- keep the old content
else -- handle mg:ignore
new_nodes [ i ] . ignore = 1 ;
end
end
return new_nodes ;
end
2017-03-28 04:50:40 +02:00
local function generate_building_what_to_place_here_and_how ( t , node_content , new_nodes , cid , keep_ground , ground_type , mirror_x , mirror_z , pos )
2017-04-03 04:24:48 +02:00
local new_content = node_content ;
2017-03-28 04:50:40 +02:00
if ( not ( t ) ) then
if ( node_content ~= cid.c_plotmarker
and ( not ( handle_schematics.moresnow_installed ) or not ( moresnow ) or node_content ~= moresnow.c_snow_top ) ) then
-- place nothing/air
return { new_content = cid.c_air , new_param2 = 0 , n = { } } ;
end
end
2017-04-03 04:24:48 +02:00
-- TODO: there ought to be no error here....
2018-07-30 04:39:23 +02:00
if ( not ( t ) or not ( t [ 1 ] ) or not ( new_nodes [ t [ 1 ] ] )
-- set air only if the new node is not of type ignore
or ( not ( new_nodes [ t [ 1 ] ] . new_content ) and not ( new_nodes [ t [ 1 ] ] . ignore ) ) ) then
2017-04-03 04:24:48 +02:00
return { new_content = cid.c_air , new_param2 = 0 , n = { } } ;
end
2017-03-28 04:50:40 +02:00
-- take care of replacements
local n = new_nodes [ t [ 1 ] ] ; -- t[1]: id of the old node
if ( not ( n.ignore ) ) then
new_content = n.new_content ;
else
new_content = node_content ;
end
-- replace all dirt and dirt with grass at that x,z coordinate with the stored ground grass node;
if ( n.is_grass and keep_ground and ground_type ) then
new_content = ground_type ;
2017-05-08 21:28:14 +02:00
elseif ( n.is_dirt and node_content ~= cid.c_air ) then
new_content = node_content ;
2017-03-28 04:50:40 +02:00
end
-- do not overwrite plotmarkers
2017-06-27 04:11:37 +02:00
if ( node_content == cid.c_plotmarker or node_content == cid.c_mob_spawner ) then
2017-03-28 04:50:40 +02:00
-- keep the old content
new_content = node_content ;
end
2017-04-03 04:24:48 +02:00
-- remove misplaced scaffolding nodes
if ( new_content == cid.c_air and ( node_content == cid.c_scaffolding or node_content == cid.c_scaffolding_empty ) ) then
new_content = cid.c_air ;
end
2017-04-24 18:04:29 +02:00
-- quite often we just need some kind of floor/ground - and do not depend on a particular node
if ( handle_schematics.also_acceptable
and new_content ~= cid.c_ignore and node_content ~= cid.c_ignore
and handle_schematics.also_acceptable [ new_content ]
and handle_schematics.also_acceptable [ new_content ] . is_ok
and handle_schematics.also_acceptable [ new_content ] . is_ok [ node_content ] ) then
new_content = node_content ;
end
2017-03-28 04:50:40 +02:00
-- the old torch is split up into three new types
if ( n.is_torch ) then
if ( t [ 2 ] == 0 ) then
new_content = cid.c_torch_ceiling ;
elseif ( t [ 2 ] == 1 ) then
new_content = cid.c_torch ;
else
new_content = cid.c_torch_wall ;
end
end
2015-05-01 18:04:03 +02:00
2017-03-28 04:50:40 +02:00
local param2 = t [ 2 ] ;
-- handle rotation
if ( n.paramtype2 ) then
if ( n.change_param2 and n.change_param2 [ t [ 2 ] ] ) then
param2 = n.change_param2 [ param2 ] ;
end
2019-06-10 03:32:54 +02:00
if ( mirror_x and param2 < 24 ) then
2017-03-28 04:50:40 +02:00
param2 = handle_schematics.rotation_table [ n.paramtype2 ] [ param2 + 1 ] [ pos.brotate + 1 ] [ 2 ] ;
2019-06-10 03:32:54 +02:00
elseif ( mirror_z and param2 < 24 ) then
2017-03-28 04:50:40 +02:00
param2 = handle_schematics.rotation_table [ n.paramtype2 ] [ param2 + 1 ] [ pos.brotate + 1 ] [ 3 ] ;
2019-06-10 03:32:54 +02:00
elseif ( param2 < 24 ) then
2017-03-28 04:50:40 +02:00
param2 = handle_schematics.rotation_table [ n.paramtype2 ] [ param2 + 1 ] [ pos.brotate + 1 ] [ 1 ] ;
end
end
-- glasslike nodes need to have param2 set to 0 (else they get a strange fill state)
if ( n.set_param2_to_0 ) then
2017-04-24 17:23:01 +02:00
param2 = 0 ;
2017-03-28 04:50:40 +02:00
end
return { new_content = new_content , new_param2 = param2 , n = n } ;
end
2017-04-03 21:33:08 +02:00
-- if scaffolding_only is set, a statistic of missing_nodes will be returned
2018-01-15 17:19:25 +01:00
handle_schematics.generate_building = function ( pos , minp , maxp , data , param2_data , a , extranodes , replacements , cid , extra_calls , building_nr_in_bpos , village_id , binfo_extra , road_node , keep_ground , scaffolding_only )
2015-05-01 18:04:03 +02:00
local binfo = binfo_extra ;
if ( not ( binfo ) and mg_villages ) then
binfo = mg_villages.BUILDINGS [ pos.btype ]
end
local scm
-- the building got removed from mg_villages.BUILDINGS in the meantime
if ( not ( binfo ) ) then
return ;
end
-- schematics of .mts type are not handled here; they need to be placed using place_schematics
if ( binfo.is_mts and binfo.is_mts == 1 ) then
return ;
end
-- roads are very simple structures that are not stored as schematics
if ( pos.btype == ' road ' ) then
handle_schematics.place_road ( minp , maxp , data , param2_data , a , road_node , pos , cid.c_air ) ;
return ;
end
if ( not ( pos.no_plotmarker ) ) then
generate_building_plotmarker ( pos , minp , maxp , data , param2_data , a , cid , building_nr_in_bpos , village_id , binfo.scm ) ;
end
-- skip building if it is not located at least partly in the area that is currently beeing generated
if ( pos.x > maxp.x or pos.x + pos.bsizex < minp.x
or pos.z > maxp.z or pos.z + pos.bsizez < minp.z ) then
return ;
end
if ( pos.btype and
( ( binfo.sizex ~= pos.bsizex and binfo.sizex ~= pos.bsizez )
or ( binfo.sizez ~= pos.bsizex and binfo.sizez ~= pos.bsizez )
or not ( binfo.scm_data_cache ) ) ) then
if ( mg_villages and mg_villages.print ) then
mg_villages.print ( mg_villages.DEBUG_LEVEL_WARNING ,
' ERROR: This village was created using diffrent buildings than those known know. Cannot place unknown building. ' ) ;
else
print ( ' ERROR: Size information about this building differs. Cannot place building. ' ) ;
end
return ;
end
if ( binfo.scm_data_cache ) then
scm = binfo.scm_data_cache ;
else
scm = binfo.scm
end
-- the fruit is set per building, not per village as the other replacements
if ( binfo.farming_plus and binfo.farming_plus == 1 and pos.fruit and mg_villages ) then
mg_villages.get_fruit_replacements ( replacements , pos.fruit ) ;
end
2017-04-03 21:33:08 +02:00
-- statistic containing information about nodes that still need to be placed (only of intrest if scaffolding_only is set)
local missing_nodes = { } ;
2015-05-01 18:04:03 +02:00
local c_ignore = minetest.get_content_id ( " ignore " )
local c_air = minetest.get_content_id ( " air " )
local c_snow = minetest.get_content_id ( " default:snow " ) ;
local c_dirt = minetest.get_content_id ( " default:dirt " ) ;
local c_dirt_with_grass = minetest.get_content_id ( " default:dirt_with_grass " ) ;
local c_dirt_with_snow = minetest.get_content_id ( " default:dirt_with_snow " ) ;
2017-03-28 04:50:40 +02:00
local c_scaffolding_empty = minetest.get_content_id ( " handle_schematics:support " ) ;
local c_scaffolding = minetest.get_content_id ( " handle_schematics:support_setup " ) ;
2016-12-28 22:31:16 +01:00
local c_dig_here = minetest.get_content_id ( " handle_schematics:dig_here " ) ;
2017-06-26 23:26:36 +02:00
-- freeze water if there is moresnow on top
cid.c_water_source = minetest.get_content_id ( " default:water_source " ) ;
cid.c_river_water_source = minetest.get_content_id ( " default:river_water_source " ) ;
cid.c_ice = minetest.get_content_id ( " default:ice " ) ;
2015-05-01 18:04:03 +02:00
local scm_x = 0 ;
local scm_z = 0 ;
local step_x = 1 ;
local step_z = 1 ;
local scm_z_start = 0 ;
if ( pos.brotate == 2 ) then
scm_x = pos.bsizex + 1 ;
step_x = - 1 ;
end
if ( pos.brotate == 1 ) then
scm_z = pos.bsizez + 1 ;
step_z = - 1 ;
scm_z_start = scm_z ;
end
local mirror_x = false ;
local mirror_z = false ;
if ( pos.mirror ) then
if ( binfo.axis and binfo.axis == 1 ) then
mirror_x = true ;
mirror_z = false ;
2017-04-03 04:24:48 +02:00
-- used for "restore original landscape"
elseif ( binfo.axis and binfo.axis == 3 ) then
mirror_z = true ;
mirror_x = true ;
2015-05-01 18:04:03 +02:00
else
mirror_x = false ;
mirror_z = true ;
end
end
-- translate all nodenames and apply the replacements
local new_nodes = generate_building_translate_nodenames ( binfo.nodenames , replacements , cid , binfo.scm , mirror_x , mirror_z ) ;
for x = 0 , pos.bsizex - 1 do
scm_x = scm_x + step_x ;
scm_z = scm_z_start ;
for z = 0 , pos.bsizez - 1 do
scm_z = scm_z + step_z ;
local xoff = scm_x ;
local zoff = scm_z ;
if ( pos.brotate == 2 ) then
if ( mirror_x ) then
xoff = pos.bsizex - scm_x + 1 ;
end
if ( mirror_z ) then
zoff = scm_z ;
else
zoff = pos.bsizez - scm_z + 1 ;
end
elseif ( pos.brotate == 1 ) then
if ( mirror_x ) then
xoff = pos.bsizez - scm_z + 1 ;
else
xoff = scm_z ;
end
if ( mirror_z ) then
zoff = pos.bsizex - scm_x + 1 ;
else
zoff = scm_x ;
end
elseif ( pos.brotate == 3 ) then
if ( mirror_x ) then
xoff = pos.bsizez - scm_z + 1 ;
else
xoff = scm_z ;
end
if ( mirror_z ) then
zoff = scm_x ;
else
zoff = pos.bsizex - scm_x + 1 ;
end
elseif ( pos.brotate == 0 ) then
if ( mirror_x ) then
xoff = pos.bsizex - scm_x + 1 ;
end
if ( mirror_z ) then
zoff = pos.bsizez - scm_z + 1 ;
end
end
local has_snow = false ;
local ground_type = c_dirt_with_grass ;
2017-04-03 04:24:48 +02:00
-- remove all dig_here-indicators
if ( scaffolding_only ) then
local ax = pos.x + x ;
local az = pos.z + z ;
for y = 0 , binfo.ysize - 1 do
local ay = pos.y + y + binfo.yoff ;
if ( ax >= minp.x and ax <= maxp.x ) and ( ay >= minp.y and ay <= maxp.y ) and ( az >= minp.z and az <= maxp.z ) then
if ( data [ a : index ( ax , ay , az ) ] == c_dig_here ) then
data [ a : index ( ax , ay , az ) ] = cid.c_air ;
-- remove old and obsolete metadata
table.insert ( extra_calls.clear_meta , { x = ax , y = ay , z = az } ) ;
end
end
end
end
2015-05-01 18:04:03 +02:00
for y = 0 , binfo.ysize - 1 do
local ax = pos.x + x ;
local ay = pos.y + y + binfo.yoff ;
local az = pos.z + z ;
if ( ax >= minp.x and ax <= maxp.x ) and ( ay >= minp.y and ay <= maxp.y ) and ( az >= minp.z and az <= maxp.z ) then
local new_content = c_air ;
2017-04-17 02:20:41 +02:00
local t = cid.c_ignore ;
if ( scm and scm [ y + 1 ] and scm [ y + 1 ] [ xoff ] ) then
t = scm [ y + 1 ] [ xoff ] [ zoff ] ;
end
2017-02-10 01:52:42 +01:00
local node_content = data [ a : index ( ax , ay , az ) ] ;
2015-05-01 18:04:03 +02:00
if ( binfo.yoff + y == 0 ) then
-- no snow on the gravel roads
if ( node_content == c_dirt_with_snow or data [ a : index ( ax , ay + 1 , az ) ] == c_snow ) then
has_snow = true ;
end
ground_type = node_content ;
end
2017-03-28 04:50:40 +02:00
-- -- we have the wrong node there
-- elseif( ((not(t) and current_content ~= cid.c_air)
-- or (t and new_nodes[t[1]] and not(new_nodes[t[1]].ignore) and current_content ~= new_nodes[ t[1]].new_content))
-- -- TODO: detect wrong rotation (param2)
--
-- and current_content ~= c_scaffolding
-- and current_content ~= c_dig_here
-- and ay<maxp.y) then
-- -- there is air above; we can place a digging indicator
-- if( data[a:index(ax, ay+1, az)] == cid.c_air or data[a:index(ax, ay+1, az)]==c_scaffolding) then
-- data[ a:index(ax, ay+1, az)] = c_dig_here;
-- end
-- end
-- which node (and which rotation) do we need here?
local res = generate_building_what_to_place_here_and_how ( t , node_content , new_nodes , cid , keep_ground , ground_type , mirror_x , mirror_z , pos )
local new_content = res.new_content ;
local param2 = res.new_param2 ;
local n = res.n ;
-- scaffolding nodes are only placed when there is air now and there ought to be a node from the building
2017-04-02 18:41:46 +02:00
if ( scaffolding_only ) then
2017-04-03 21:33:08 +02:00
-- new_content is adjusted later on, so store here what might be missing so that we can create the missing_nodes statistic
local new_content_wanted = new_content ;
2017-04-03 04:24:48 +02:00
-- a node is to be placed here AND it is diffrent from the existing one AND
-- the existing node is not air, scaffolding, special scaffolding or a dig-here-indicator
-- -> the existing node needs to be digged
2017-04-02 18:41:46 +02:00
if ( new_content and new_content ~= node_content
2018-08-04 00:05:28 +02:00
and node_content ~= cid.c_air and node_content ~= c_scaffolding and node_content ~= c_scaffolding_empty
-- if this is just a plant in a diffrent growth stage: ignore it
and not ( handle_schematics.player_can_provide [ new_content ] and
handle_schematics.player_can_provide [ new_content ] ==
handle_schematics.player_can_provide [ node_content ] ) ) then
2017-04-02 18:41:46 +02:00
local h ;
2017-04-03 04:24:48 +02:00
-- search upward for the first empty (air) node or dig-here-indicator and place a dig_here-indicator
2017-04-02 18:41:46 +02:00
for h = ay , maxp.y do
2017-04-03 04:24:48 +02:00
local node_here = data [ a : index ( ax , h , az ) ] ;
if ( node_here == cid.c_air or node_here == c_dig_here or node_here == c_scaffolding or node_here == c_scaffolding_empty ) then
2017-04-02 18:41:46 +02:00
if ( data [ a : index ( ax , h , az ) ] ~= c_dig_here ) then
2017-05-28 23:54:09 +02:00
table.insert ( extra_calls.scaffolding , { x = ax , y = h , z = az , dig_down = h - ay , what_where = { { ay , new_content , param2 } } } ) ;
else
-- store which node needs to be placed at which height
for i , v in ipairs ( extra_calls.scaffolding ) do
if ( v.x == ax and v.y == h and v.z == az ) then
table.insert ( v.what_where , { ay , new_content , param2 } ) ;
end
end
2017-04-02 18:41:46 +02:00
end
data [ a : index ( ax , h , az ) ] = c_dig_here ;
2017-04-03 21:33:08 +02:00
-- how much is to be digged is counted later on (when evaluating extra_calls.scaffolding)
2017-04-02 18:41:46 +02:00
break ;
end
end
-- keep the old content
new_content = node_content ;
param2 = param2_data [ a : index ( ax , ay , az ) ] ;
n = { } ;
2017-04-03 04:24:48 +02:00
-- a new node is to be placed here AND it is not air or ignore AND
-- the existing node is either air, scaffolding or special scaffolding
-- -> place special scaffolding to indicate which node is wanted here
2017-04-02 18:41:46 +02:00
elseif ( new_content and new_content ~= cid.c_air and new_content ~= cid.c_ignore
and ( node_content == cid.c_air or node_content == c_scaffolding or node_content == c_scaffolding_empty ) ) then
2017-03-28 04:50:40 +02:00
-- store what we expect/want at this place
table.insert ( extra_calls.scaffolding , { x = ax , y = ay , z = az , node_wanted = new_content , param2_wanted = param2 } ) ;
-- place scaffolding instead of the wanted node
2017-04-03 04:24:48 +02:00
-- TODO: count how many scaffolding nodes where placed
2017-03-28 04:50:40 +02:00
new_content = c_scaffolding ;
param2 = 0 ;
n = { } ;
2017-04-03 04:24:48 +02:00
-- a new node is to be placed here AND it is air AND
-- there is a scaffolding node already
-- -> remove this misplaced scaffolding node
elseif ( new_content and new_content == cid.c_air
and ( node_content == c_scaffolding or node_content == c_scaffolding_empty ) ) then
-- we need to remove metadata at this position
table.insert ( extra_calls.clear_meta , { x = ax , y = ay , z = az } ) ;
new_content = cid.c_air ;
param2 = 0 ;
n = { } ;
-- let the old node continue to exist
2015-05-01 18:04:03 +02:00
else
new_content = node_content ;
2017-03-28 04:50:40 +02:00
param2 = param2_data [ a : index ( ax , ay , az ) ] ;
n = { } ;
2015-05-01 18:04:03 +02:00
end
2017-04-03 21:33:08 +02:00
-- create a statistic of all missing nodes
if ( node_content ~= new_content_wanted and node_content and new_content_wanted
2018-08-04 01:09:53 +02:00
and new_content_wanted ~= cid.c_air and new_content_wanted ~= cid.c_ignore
and not ( handle_schematics.player_can_provide [ new_content ] and
handle_schematics.player_can_provide [ new_content ] ==
handle_schematics.player_can_provide [ node_content ] ) ) then
2017-04-03 21:33:08 +02:00
if ( not ( missing_nodes [ new_content_wanted ] ) ) then
missing_nodes [ new_content_wanted ] = 1 ;
else
missing_nodes [ new_content_wanted ] = missing_nodes [ new_content_wanted ] + 1 ;
end
end
2017-03-28 04:50:40 +02:00
end
2015-05-01 18:04:03 +02:00
2017-03-28 04:50:40 +02:00
-- actually change the node
data [ a : index ( ax , ay , az ) ] = new_content ;
param2_data [ a : index ( ax , ay , az ) ] = param2 ;
2015-05-01 18:04:03 +02:00
2017-03-28 04:50:40 +02:00
-- some nodes need on_construct to be called in order to be set up properly
if ( n.on_construct ) then
if ( not ( extra_calls.on_constr [ new_content ] ) ) then
extra_calls.on_constr [ new_content ] = { { x = ax , y = ay , z = az } } ;
2015-05-01 18:04:03 +02:00
else
2017-03-28 04:50:40 +02:00
table.insert ( extra_calls.on_constr [ new_content ] , { x = ax , y = ay , z = az } ) ;
2015-05-01 18:04:03 +02:00
end
2017-03-28 04:50:40 +02:00
end
-- store that a tree is to be grown there
if ( n.is_tree ) then
table.insert ( extra_calls.trees , { x = ax , y = ay , z = az , typ = new_content , snow = has_snow } ) ;
2016-03-20 23:57:53 +01:00
2017-03-28 04:50:40 +02:00
-- we're dealing with a chest that might need filling
elseif ( n.is_chestlike ) then
table.insert ( extra_calls.chests , { x = ax , y = ay , z = az , typ = new_content , bpos_i = building_nr_in_bpos , typ_name = n.special_chest } ) ;
2016-03-20 23:57:53 +01:00
2017-03-28 04:50:40 +02:00
-- the sign may require some text to be written on it
elseif ( n.is_sign ) then
table.insert ( extra_calls.signs , { x = ax , y = ay , z = az , typ = new_content , bpos_i = building_nr_in_bpos } ) ;
-- doors need the state param to be set (which depends on param2)
elseif ( n.is_door_a ) then
table.insert ( extra_calls.door_a , { x = ax , y = ay , z = az , typ = new_content , p2 = param2_data [ a : index ( ax , ay , az ) ] } ) ;
elseif ( n.is_door_b ) then
table.insert ( extra_calls.door_b , { x = ax , y = ay , z = az , typ = new_content , p2 = param2_data [ a : index ( ax , ay , az ) ] } ) ;
2017-06-05 14:47:15 +02:00
-- beds are of special intrest to npc
elseif ( n.is_bed ) then
2017-06-09 23:08:22 +02:00
local found = false ;
for i , bed in ipairs ( extra_calls.beds ) do
if ( bed and bed.x == ax and bed.y == ay and bed.z == az ) then
found = true ;
end
end
if ( not ( found ) ) then
table.insert ( extra_calls.beds , { x = ax , y = ay , z = az , typ = new_content , p2 = param2_data [ a : index ( ax , ay , az ) ] } ) ;
end
2017-07-20 05:47:55 +02:00
-- workplace markers need to know their village_id, plot_nr etc. as well
elseif ( n.is_workplace_marker ) then
local found = false ;
for i , w in ipairs ( extra_calls.workplaces ) do
if ( w and w.x == ax and w.y == ay and w.z == az ) then
found = true ;
end
end
if ( not ( found ) ) then
table.insert ( extra_calls.workplaces , { x = ax , y = ay , z = az , typ = new_content , p2 = param2_data [ a : index ( ax , ay , az ) ] } ) ;
end
2015-05-01 18:04:03 +02:00
end
end
end
local ax = pos.x + x ;
local az = pos.z + z ;
local y_top = pos.y + binfo.yoff + binfo.ysize ;
if ( y_top + 1 > maxp.y ) then
y_top = maxp.y - 1 ;
end
local y_bottom = pos.y + binfo.yoff ;
if ( y_bottom < minp.y ) then
y_bottom = minp.y ;
end
if ( has_snow and ax >= minp.x and ax <= maxp.x and az >= minp.z and az <= maxp.z ) then
2017-06-26 23:26:36 +02:00
local res = handle_schematics.mg_drop_moresnow ( ax , az , y_top , y_bottom - 1 , a , data , param2_data , cid ) ;
2015-05-01 18:04:03 +02:00
if ( res and ( data [ a : index ( ax , res.height , az ) ] == cid.c_air
or data [ a : index ( ax , res.height , az ) ] == cid.c_water ) ) then
data [ a : index ( ax , res.height , az ) ] = res.suggested . new_id ;
param2_data [ a : index ( ax , res.height , az ) ] = res.suggested . param2 ;
has_snow = false ;
end
end
end
end
2017-04-03 21:33:08 +02:00
if ( scaffolding_only ) then
return missing_nodes ;
end
2015-05-01 18:04:03 +02:00
end
-- actually place the buildings (at least those which came as .we files; .mts files are handled later on)
-- this code was also responsible for tree placement;
-- place_buildings is used by mg_villages exclusively. It calls the local function generate_building and
-- therefore resides in this file.
handle_schematics.place_buildings = function ( village , minp , maxp , data , param2_data , a , cid , village_id )
-- this function is only relevant for mg_villages
if ( not ( mg_villages ) ) then
return ;
end
local vx , vz , vs , vh = village.vx , village.vz , village.vs , village.vh
local village_type = village.village_type ;
local bpos = village.to_add_data . bpos ;
local replacements = mg_villages.get_replacement_table ( village.village_type , nil , village.to_add_data . replacements ) ;
cid.c_chest = handle_schematics.get_content_id_replaced ( ' default:chest ' , replacements ) ;
2017-02-25 19:44:30 +01:00
cid.c_bookshelf = handle_schematics.get_content_id_replaced ( ' default:bookshelf ' , replacements ) ;
2015-05-01 18:04:03 +02:00
cid.c_chest_locked = handle_schematics.get_content_id_replaced ( ' default:chest_locked ' , replacements ) ;
cid.c_chest_shelf = handle_schematics.get_content_id_replaced ( ' cottages:shelf ' , replacements ) ;
cid.c_chest_ash = handle_schematics.get_content_id_replaced ( ' trees:chest_ash ' , replacements ) ;
cid.c_chest_aspen = handle_schematics.get_content_id_replaced ( ' trees:chest_aspen ' , replacements ) ;
cid.c_chest_birch = handle_schematics.get_content_id_replaced ( ' trees:chest_birch ' , replacements ) ;
cid.c_chest_maple = handle_schematics.get_content_id_replaced ( ' trees:chest_maple ' , replacements ) ;
cid.c_chest_chestnut = handle_schematics.get_content_id_replaced ( ' trees:chest_chestnut ' , replacements ) ;
cid.c_chest_pine = handle_schematics.get_content_id_replaced ( ' trees:chest_pine ' , replacements ) ;
cid.c_chest_spruce = handle_schematics.get_content_id_replaced ( ' trees:chest_spruce ' , replacements ) ;
cid.c_sign = handle_schematics.get_content_id_replaced ( ' default:sign_wall ' , replacements ) ;
2017-02-10 01:26:16 +01:00
cid.c_torch = handle_schematics.get_content_id_replaced ( ' default:torch ' , replacements ) ;
cid.c_torch_ceiling = handle_schematics.get_content_id_replaced ( ' default:torch_ceiling ' , replacements ) ;
cid.c_torch_wall = handle_schematics.get_content_id_replaced ( ' default:torch_wall ' , replacements ) ;
2015-05-01 18:04:03 +02:00
--print('REPLACEMENTS: '..minetest.serialize( replacements.table )..' CHEST: '..tostring( minetest.get_name_from_content_id( cid.c_chest ))); -- TODO
local extranodes = { }
2017-07-20 05:47:55 +02:00
local extra_calls = { on_constr = { } , trees = { } , chests = { } , signs = { } , traders = { } , door_a = { } , door_b = { } , scaffolding = { } , clear_meta = { } , beds = { } , workplaces = { } } ;
2015-05-01 18:04:03 +02:00
for i , pos in ipairs ( bpos ) do
-- roads are only placed if there are at least mg_villages.MINIMAL_BUILDUNGS_FOR_ROAD_PLACEMENT buildings in the village
if ( not ( pos.btype ) or pos.btype ~= ' road ' or village.anz_buildings > mg_villages.MINIMAL_BUILDUNGS_FOR_ROAD_PLACEMENT ) then
-- replacements are in table format for mapgen-based building spawning
2015-07-02 01:56:28 +02:00
local road_material = mg_villages.road_node ;
if ( pos.road_material ) then
road_material = pos.road_material ;
end
2017-06-05 14:47:15 +02:00
-- we need to collect the positions of all beds...even if they are placed in diffrent mapchunks
if ( not ( pos.beds ) ) then
pos.beds = { } ;
end
extra_calls.beds = pos.beds ;
2017-07-20 05:47:55 +02:00
if ( not ( pos.workplaces ) ) then
pos.workplaces = { } ;
end
extra_calls.workplaces = pos.workplaces ;
2016-12-28 22:31:16 +01:00
-- do not use scaffolding here; place the building directly
2018-01-15 17:19:25 +01:00
handle_schematics.generate_building ( pos , minp , maxp , data , param2_data , a , extranodes , replacements , cid , extra_calls , i , village_id , nil , road_material , true , false )
2017-06-05 14:47:15 +02:00
-- the bed positions are of intrest later on
pos.beds = extra_calls.beds ;
2017-07-20 05:47:55 +02:00
pos.workplaces = extra_calls.workplaces ;
2015-05-01 18:04:03 +02:00
end
end
2017-06-05 14:47:15 +02:00
-- we store the beds per building; not per village
extra_calls.beds = nil ;
2017-07-20 05:47:55 +02:00
extra_calls.workplaces = nil ;
2015-05-01 18:04:03 +02:00
-- replacements are in list format for minetest.place_schematic(..) type spawning
return { extranodes = extranodes , bpos = bpos , replacements = replacements.list , dirt_roads = village.to_add_data . dirt_roads ,
plantlist = village.to_add_data . plantlist , extra_calls = extra_calls } ;
end
2018-01-15 17:19:25 +01:00
-- get content ids replaced
handle_schematics.get_cid_table = function ( replacements )
-- only very few nodes are actually used from the cid table (content ids)
local cid = { } ;
cid.c_air = minetest.get_content_id ( ' air ' ) ;
cid.c_dirt = handle_schematics.get_content_id_replaced ( ' default:dirt ' , replacements ) ;
cid.c_dirt_with_grass = handle_schematics.get_content_id_replaced ( ' default:dirt_with_grass ' , replacements ) ;
cid.c_sapling = handle_schematics.get_content_id_replaced ( ' default:sapling ' , replacements ) ;
cid.c_jsapling = handle_schematics.get_content_id_replaced ( ' default:junglesapling ' , replacements ) ;
cid.c_psapling = handle_schematics.get_content_id_replaced ( ' default:pine_sapling ' , replacements ) ;
cid.c_asapling = handle_schematics.get_content_id_replaced ( ' default:acacia_sapling ' , replacements ) ;
cid.c_aspsapling = handle_schematics.get_content_id_replaced ( ' default:aspen_sapling ' , replacements ) ;
cid.c_savannasapling = handle_schematics.get_content_id_replaced ( ' mg:savannasapling ' , replacements ) ;
cid.c_pinesapling = handle_schematics.get_content_id_replaced ( ' mg:pinesapling ' , replacements ) ;
cid.c_plotmarker = minetest.get_content_id ( ' mg_villages:plotmarker ' ) ;
cid.c_mob_spawner = minetest.get_content_id ( ' mg_villages:mob_spawner ' ) ;
cid.c_chest = handle_schematics.get_content_id_replaced ( ' default:chest ' , replacements ) ;
cid.c_chest_locked = handle_schematics.get_content_id_replaced ( ' default:chest_locked ' , replacements ) ;
cid.c_chest_shelf = handle_schematics.get_content_id_replaced ( ' cottages:shelf ' , replacements ) ;
cid.c_chest_ash = handle_schematics.get_content_id_replaced ( ' trees:chest_ash ' , replacements ) ;
cid.c_chest_aspen = handle_schematics.get_content_id_replaced ( ' trees:chest_aspen ' , replacements ) ;
cid.c_chest_birch = handle_schematics.get_content_id_replaced ( ' trees:chest_birch ' , replacements ) ;
cid.c_chest_maple = handle_schematics.get_content_id_replaced ( ' trees:chest_maple ' , replacements ) ;
cid.c_chest_chestnut = handle_schematics.get_content_id_replaced ( ' trees:chest_chestnut ' , replacements ) ;
cid.c_chest_pine = handle_schematics.get_content_id_replaced ( ' trees:chest_pine ' , replacements ) ;
cid.c_chest_spruce = handle_schematics.get_content_id_replaced ( ' trees:chest_spruce ' , replacements ) ;
cid.c_sign = handle_schematics.get_content_id_replaced ( ' default:sign_wall ' , replacements ) ;
cid.c_torch = handle_schematics.get_content_id_replaced ( ' default:torch ' , replacements ) ;
cid.c_torch_ceiling = handle_schematics.get_content_id_replaced ( ' default:torch_ceiling ' , replacements ) ;
cid.c_torch_wall = handle_schematics.get_content_id_replaced ( ' default:torch_wall ' , replacements ) ;
-- for roads
cid.c_sign = handle_schematics.get_content_id_replaced ( ' default:gravel ' , replacements ) ;
2019-10-17 00:45:29 +02:00
-- additional entries from mg_villages
cid.c_ignore = minetest.get_content_id ( ' ignore ' ) ;
cid.c_stone = minetest.get_content_id ( ' default:stone ' ) ;
cid.c_snow = minetest.get_content_id ( ' default:snow ' ) ;
cid.c_snowblock = minetest.get_content_id ( ' default:snowblock ' ) ;
cid.c_dirt_with_snow = minetest.get_content_id ( ' default:dirt_with_snow ' ) ;
cid.c_desert_sand = minetest.get_content_id ( ' default:desert_sand ' ) ; -- PM v
cid.c_desert_stone = minetest.get_content_id ( ' default:desert_stone ' ) ;
cid.c_silver_sand = minetest.get_content_id ( ' default:silver_sand ' ) ; -- PM v
cid.c_silver_sandstone = minetest.get_content_id ( ' default:silver_sandstone ' ) ;
cid.c_sand = minetest.get_content_id ( ' default:sand ' ) ;
cid.c_tree = minetest.get_content_id ( ' default:tree ' ) ;
cid.c_jtree = minetest.get_content_id ( ' default:jungletree ' ) ;
cid.c_ptree = minetest.get_content_id ( ' default:pine_tree ' ) ;
cid.c_atree = minetest.get_content_id ( ' default:acacia_tree ' ) ;
cid.c_asptree = minetest.get_content_id ( ' default:aspen_tree ' ) ;
cid.c_water = minetest.get_content_id ( ' default:water_source ' ) ; -- PM ^
cid.c_stone_with_coal = minetest.get_content_id ( ' default:stone_with_coal ' ) ;
cid.c_sandstone = minetest.get_content_id ( ' default:sandstone ' ) ;
cid.c_msnow_1 = minetest.get_content_id ( ' moresnow:snow_top ' ) ;
cid.c_msnow_2 = minetest.get_content_id ( ' moresnow:snow_fence_top ' ) ;
cid.c_msnow_3 = minetest.get_content_id ( ' moresnow:snow_stair_top ' ) ;
cid.c_msnow_4 = minetest.get_content_id ( ' moresnow:snow_slab_top ' ) ;
cid.c_msnow_5 = minetest.get_content_id ( ' moresnow:snow_panel_top ' ) ;
cid.c_msnow_6 = minetest.get_content_id ( ' moresnow:snow_micro_top ' ) ;
cid.c_msnow_7 = minetest.get_content_id ( ' moresnow:snow_outer_stair_top ' ) ;
cid.c_msnow_8 = minetest.get_content_id ( ' moresnow:snow_inner_stair_top ' ) ;
cid.c_msnow_9 = minetest.get_content_id ( ' moresnow:snow_ramp_top ' ) ;
cid.c_msnow_10 = minetest.get_content_id ( ' moresnow:snow_ramp_outer_top ' ) ;
cid.c_msnow_11 = minetest.get_content_id ( ' moresnow:snow_ramp_inner_top ' ) ;
cid.c_msnow_soil = minetest.get_content_id ( ' moresnow:snow_soil ' ) ;
cid.c_ice = minetest.get_content_id ( ' default:ice ' ) ;
if ( minetest.get_modpath ( ' ethereal ' ) ) then
cid.c_ethereal_clay_red = minetest.get_content_id ( ' bakedclay:red ' ) ;
cid.c_ethereal_clay_orange = minetest.get_content_id ( ' bakedclay:orange ' ) ;
end
2018-01-15 17:19:25 +01:00
return cid ;
end
2015-05-01 18:04:03 +02:00
-- place a schematic manually
--
-- pos needs to contain information about how to place the building:
-- pos.x, pos.y, pos.z where the building is to be placed
-- pos.btype determines which building will be placed; if not set, binfo_extra needs to be provided
-- pos.brotate contains a value of 0-3, which determines the rotation of the building
-- pos.bsizex size of the building in x direction
-- pos.bsizez size of the building in z direction
-- pos.mirror if set, the building will be mirrored
-- pos.no_plotmarker optional; needs to be set in order to avoid the generation of a plotmarker
-- building_nr optional; used for plotmarker
-- village_id optional; used for plotmarker
-- pos.fruit optional; determines the fruit a farm is going to grow (if binfo.farming_plus is set)
-- binfo contains general information about a building:
-- binfo.sizex size of the building in x direction
-- binfo.sizez
-- binfo.ysize
-- binfo.yoff how deep is the building burried?
-- binfo.nodenames list of the node names beeing used by the building
-- binfo.scm name of the file containing the schematic; only needed for an error message
-- binfo.scm_data_cache contains actual information about the nodes beeing used (the data)
-- binfo.is_mts optional; if set to 1, the function will abort
-- binfo.farming_plus optional; if set, pos.fruit needs to be set as well
-- binfo.axis optional; relevant for some mirroring operations
--
-- replacement_list contains replacements in the same list format as place_schematic uses
2016-12-28 22:31:16 +01:00
-- keep_ground keep biome-specific ground nodes
-- scaffolding_only when true: place a scaffolding node where there is air; place nothing if there is a solid node
2015-05-01 18:04:03 +02:00
--
2016-12-28 22:31:16 +01:00
handle_schematics.place_building_using_voxelmanip = function ( pos , binfo , replacement_list , keep_ground , scaffolding_only )
2015-05-01 18:04:03 +02:00
if ( not ( replacement_list ) or type ( replacement_list ) ~= ' table ' ) then
return ;
end
-- if not defined, the building needs to start at pos.x,pos.y,pos.z - without offset
if ( not ( binfo.yoff ) ) then
binfo.yoff = 0 ;
end
-- TODO: calculate the end position from the given data
-- get a suitable voxelmanip object
-- (taken from minetest_game/mods/default/trees.lua)
local vm = minetest.get_voxel_manip ( )
local minp , maxp = vm : read_from_map (
{ x = pos.x , y = pos.y , z = pos.z } ,
2016-12-28 22:31:16 +01:00
-- add one in height in case we need to add a dig_here-indicator
{ x = pos.x + pos.bsizex , y = pos.y + binfo.ysize + 1 , z = pos.z + pos.bsizez } -- TODO
2015-05-01 18:04:03 +02:00
)
local a = VoxelArea : new ( { MinEdge = minp , MaxEdge = maxp } )
local data = vm : get_data ( )
local param2_data = vm : get_param2_data ( ) ;
-- translate the replacement_list into replacements.ids and replacements.table format
-- the first two parameters are nil because we do not want a new replacement list to be generated
local replacements = handle_schematics.get_replacement_table ( nil , nil , replacement_list ) ;
2018-01-15 17:19:25 +01:00
-- get content id table
local cid = handle_schematics.get_cid_table ( replacements ) ;
2015-05-01 18:04:03 +02:00
local extranodes = { }
2017-07-20 05:47:55 +02:00
local extra_calls = { on_constr = { } , trees = { } , chests = { } , signs = { } , traders = { } , door_a = { } , door_b = { } , scaffolding = { } , clear_meta = { } , beds = { } , workplaces = { } } ;
2015-05-01 18:04:03 +02:00
2015-07-10 21:11:30 +02:00
-- last parameter false -> place dirt nodes instead of trying to keep the ground nodes
2018-01-15 17:19:25 +01:00
local missing_nodes = handle_schematics.generate_building ( pos , minp , maxp , data , param2_data , a , extranodes , replacements , cid , extra_calls , pos.building_nr , pos.village_id , binfo , cid.c_gravel , keep_ground , scaffolding_only ) ;
2015-05-01 18:04:03 +02:00
-- store the changed map data
vm : set_data ( data ) ;
vm : set_param2_data ( param2_data ) ;
vm : write_to_map ( ) ;
vm : update_liquids ( ) ;
vm : update_map ( ) ;
-- TODO: do the calls for the extranodes as well
-- replacements are in list format for minetest.place_schematic(..) type spawning
2017-04-03 21:33:08 +02:00
return { extranodes = extranodes , replacements = replacements.list , extra_calls = extra_calls , missing_nodes = missing_nodes } ;
2015-05-01 18:04:03 +02:00
end
2017-05-28 23:54:09 +02:00
-- helper function for handle_schematics.place_building_from_file; also used
-- when digging below a dig_here indicator
handle_schematics.setup_scaffolding = function ( v )
local node_name = minetest.get_name_from_content_id ( v.node_wanted ) ;
local descr = tostring ( node_name ) ;
2017-06-26 23:26:36 +02:00
local node_def = handle_schematics.node_defined ( node_name ) ;
if ( node_def and node_def.drop
-- the drop can be a craftitem
and minetest.registered_items [ node_def.drop ]
and not ( handle_schematics.direct_instead_of_drop [ node_name ] ) ) then
descr = minetest.registered_items [ node_def.drop ] . description ;
elseif ( node_def and node_def.description ) then
descr = node_def.description ;
else
descr = " - ? - " ;
2017-05-28 23:54:09 +02:00
end
local meta = minetest.get_meta ( v ) ;
meta : set_string ( " node_wanted " , node_name ) ;
meta : set_int ( " param2_wanted " , v.param2_wanted ) ;
meta : set_string ( " infotext " , " Needed: " .. descr ) ;
end
2015-05-01 18:04:03 +02:00
-- places a building read from file "building_name" on the map between start_pos and end_pos using luavoxelmanip
-- returns error message on failure and nil on success
2019-06-10 03:32:33 +02:00
handle_schematics.place_building_from_file_or_cache = function ( start_pos , end_pos , building_name , replacement_list , rotate , axis , mirror , no_plotmarker , keep_ground , scaffolding_only , plotmarker_pos , binfo )
2017-03-28 04:50:40 +02:00
--print ("scaffolding place_building_from_file: "..minetest.serialize( scaffolding_only ));
2015-05-01 18:04:03 +02:00
if ( not ( building_name ) ) then
return " No file name given. Cannot find the schematic. " ;
end
2019-06-10 03:32:33 +02:00
if ( not ( binfo ) ) then
binfo = handle_schematics.analyze_file ( building_name , nil , nil ) ;
end
2015-05-01 18:04:03 +02:00
if ( not ( binfo ) ) then
return " Failed to import schematic. Only .mts and .we are supported! " ;
end
-- this value has already been taken care of when determining start_pos
binfo.yoff = 0 ;
-- file name of the scm; only used for error messages
binfo.scm = building_name ;
-- this is relevant for mirroring operations
binfo.axis = axis ;
if ( not ( rotate ) or rotate == " 0 " ) then
start_pos.brotate = 0 ;
elseif ( rotate == " 90 " ) then
start_pos.brotate = 1 ;
elseif ( rotate == " 180 " ) then
start_pos.brotate = 2 ;
elseif ( rotate == " 270 " ) then
start_pos.brotate = 3 ;
end
if ( start_pos.brotate > 3 ) then
start_pos.brotate = start_pos.brotate % 4 ;
end
-- determine the size of the bulding from the place we assigned to it...
start_pos.bsizex = math.abs ( end_pos.x - start_pos.x ) + 1 ;
start_pos.bsizez = math.abs ( end_pos.z - start_pos.z ) + 1 ;
-- otpional; if set, the building will be mirrored
start_pos.mirror = mirror ;
-- do not generate a plot marker as this is not part of a village;
-- otherwise, building_nr and village_id would have to be provided
start_pos.no_plotmarker = no_plotmarker ;
-- all those calls to on_construct need to be done now
2016-12-28 22:31:16 +01:00
local res = handle_schematics.place_building_using_voxelmanip ( start_pos , binfo , replacement_list , keep_ground , scaffolding_only ) ;
2015-05-01 18:04:03 +02:00
if ( not ( res ) or not ( res.extra_calls ) ) then
return ;
end
2017-04-03 04:24:48 +02:00
-- clear metadata where needed
for k , v in pairs ( res.extra_calls . clear_meta ) do
local meta = minetest.get_meta ( v ) ;
-- clear metadata at this position
meta : from_table ( { inventory = { } , fields = { } } ) ;
v = nil ;
end
2018-01-11 19:02:36 +01:00
-- do the necessary on_construct calls that mostly affect metadata
handle_schematics.call_on_construct ( res.extra_calls . on_constr ) ;
-- set up doors properly (to whatever minetest_game currently demands)
handle_schematics.call_door_setup ( res.extra_calls . door_b ) ;
2016-03-20 23:57:53 +01:00
2015-07-06 18:01:02 +02:00
if ( binfo.metadata ) then
-- if it is a .we/.wem file, metadata was included directly
handle_schematics.restore_meta ( nil , binfo.metadata , start_pos , end_pos , start_pos.brotate , mirror ) ;
else
-- .mts files come with extra .meta file (if such a .meta file was created)
-- TODO: restore metadata for .mts files
--handle_schematics.restore_meta( filename, nil, binfo.metadata, start_pos, end_pos, start_pos.brotate, mirror);
end
2017-03-28 04:50:40 +02:00
2017-04-03 21:33:08 +02:00
local nodes_to_dig = 0 ;
2017-03-28 04:50:40 +02:00
for k , v in pairs ( res.extra_calls . scaffolding ) do
2017-04-02 18:41:46 +02:00
if ( v.node_wanted ) then
2017-05-28 23:54:09 +02:00
handle_schematics.setup_scaffolding ( v ) ;
2017-03-28 04:50:40 +02:00
2017-04-02 18:41:46 +02:00
elseif ( v.dig_down ) then
local meta = minetest.get_meta ( v ) ;
if ( v.dig_down > 1 ) then
meta : set_string ( " infotext " , " Dig " .. v.dig_down .. " blocks down here. " ) ;
else
meta : set_string ( " infotext " , " Dig the block below. " ) ;
end
2017-05-28 23:54:09 +02:00
meta : set_string ( " dig_down " , v.dig_down ) ;
-- structure of what_where = { pos_y, new_content, param2}}
meta : set_string ( " node_wanted_down_there " , minetest.serialize ( v.what_where ) ) ;
2017-04-03 21:37:04 +02:00
-- store the position of the build chest so that npc can locate it more easily
2017-04-03 21:44:22 +02:00
if ( plotmarker_pos ) then
meta : set_string ( " chest_pos " , minetest.pos_to_string ( plotmarker_pos , 0 ) ) ;
end
2017-04-03 21:33:08 +02:00
-- count them
nodes_to_dig = nodes_to_dig + v.dig_down ;
end
end
2017-04-04 02:52:18 +02:00
-- we need to store additional information at the plotmarkers position
if ( plotmarker_pos ) then
local meta = minetest.get_meta ( plotmarker_pos ) ;
-- how many nodes need to be digged here?
meta : set_int ( " nodes_to_dig " , nodes_to_dig ) ;
2017-04-24 21:08:22 +02:00
local nodes_to_place = 0 ;
2017-04-04 02:52:18 +02:00
if ( not ( res.missing_nodes ) ) then
res.missing_nodes = { } ;
end
2017-04-03 21:33:08 +02:00
local missing = { } ;
2017-04-04 02:52:18 +02:00
local inv = meta : get_inventory ( ) ;
inv : set_size ( " needed " , 48 ) ;
2017-04-03 21:33:08 +02:00
for k , v in pairs ( res.missing_nodes ) do
2017-04-04 02:52:18 +02:00
local node_wanted = minetest.get_name_from_content_id ( k ) ;
-- some nodes - like i.e. dirt_with_grass - cannot be obtained by the player directly
2017-04-25 17:39:41 +02:00
node_wanted = handle_schematics.get_what_player_can_provide ( node_wanted ) ;
2017-04-04 02:52:18 +02:00
-- store how many are needed
if ( missing [ node_wanted ] ) then
missing [ node_wanted ] = missing [ node_wanted ] + v ;
elseif ( node_wanted ~= " " ) then -- "" may happen with the top of doors etc.
missing [ node_wanted ] = v ;
end
end
2017-04-04 04:17:46 +02:00
local i = 1 ;
2017-04-04 02:52:18 +02:00
-- now turn that information into actual stacks
for k , v in pairs ( missing ) do
if ( i < 48 ) then
local stack = inv : get_stack ( " needed " , i ) ;
stack : set_name ( k ) ;
stack : set_count ( v ) ;
inv : set_stack ( " needed " , i , stack ) ;
2017-04-24 21:08:22 +02:00
nodes_to_place = nodes_to_place + v ;
2017-04-04 02:52:18 +02:00
i = i + 1 ;
end
end
-- clear the rest of the inventory
while ( i < 48 ) do
local stack = inv : get_stack ( " needed " , i ) ;
stack : set_name ( " " ) ;
stack : set_count ( 0 ) ;
inv : set_stack ( " needed " , i , stack ) ;
i = i + 1 ;
2017-04-02 18:41:46 +02:00
end
2017-04-24 21:08:22 +02:00
meta : set_int ( " nodes_to_place " , nodes_to_place ) ;
2017-03-28 04:50:40 +02:00
end
2015-05-01 18:04:03 +02:00
end
-- add the dirt roads
handle_schematics.place_dirt_roads = function ( village , minp , maxp , data , param2_data , a , c_road_node )
local c_air = minetest.get_content_id ( ' air ' ) ;
for _ , pos in ipairs ( village.to_add_data . dirt_roads ) do
handle_schematics.place_road ( minp , maxp , data , param2_data , a , c_road_node , pos , c_air ) ;
end
end
handle_schematics.place_road = function ( minp , maxp , data , param2_data , a , c_road_node , pos , c_air )
local param2 = 0 ;
2015-07-02 01:56:28 +02:00
if ( pos.bsizex > 2 and pos.bsizex > pos.bsizez ) then
2015-05-01 18:04:03 +02:00
param2 = 1 ;
end
2015-07-02 01:56:28 +02:00
--[[
local is_main_road = false ;
local c_road_node = minetest.get_content_id ( ' default:coalblock ' ) ;
local c_middle_wool = minetest.get_content_id ( ' default:clay ' ) ;
local slab_stone = minetest.get_content_id ( ' stairs:slab_stone ' ) ;
if ( pos.bsizex > 2 and pos.bsizez > 2 ) then
is_main_road = true ;
end
--]]
2015-05-01 18:04:03 +02:00
if ( not ( pos.y >= minp.y and pos.y <= maxp.y - 2 ) ) then
return ;
end
for x = math.max ( pos.x , minp.x ) , math.min ( pos.x + pos.bsizex - 1 , maxp.x ) do
for z = math.max ( pos.z , minp.z ) , math.min ( pos.z + pos.bsizez - 1 , maxp.z ) do
-- roads have a height of 1 block
data [ a : index ( x , pos.y , z ) ] = c_road_node ;
param2_data [ a : index ( x , pos.y , z ) ] = param2 ;
-- ...with air above
data [ a : index ( x , pos.y + 1 , z ) ] = c_air ;
data [ a : index ( x , pos.y + 2 , z ) ] = c_air ;
2015-07-02 01:56:28 +02:00
--[[
if ( ( param2 == 0 and ( x == pos.x or x == pos.x + 8 ) and is_main_road )
or ( param2 == 1 and ( z == pos.z or z == pos.z + 8 ) and is_main_road ) ) then
data [ a : index ( x , pos.y + 1 , z ) ] = slab_stone ;
elseif ( ( param2 == 0 and ( x == pos.x + 4 ) and is_main_road )
or ( param2 == 1 and ( z == pos.z + 4 ) and is_main_road ) ) then
data [ a : index ( x , pos.y , z ) ] = c_middle_wool ;
end
--]]
2015-05-01 18:04:03 +02:00
end
end
end
2016-06-15 02:36:49 +02:00
-- the node layer at height "ground_level" is not touched; thus
-- dirt/sand/whatever can remain there (=biome dependant); this
-- also means that the foundations for the ex-building's walls
-- will keep standing
handle_schematics.clear_area = function ( start_pos , end_pos , ground_level )
local vm = minetest.get_voxel_manip ( )
local minp , maxp = vm : read_from_map (
{ x = start_pos.x , y = start_pos.y , z = start_pos.z } ,
{ x = end_pos.x , y = end_pos.y , z = end_pos.z }
)
local a = VoxelArea : new ( { MinEdge = minp , MaxEdge = maxp } )
local data = vm : get_data ( )
if ( ground_level < start_pos.y or ground_level > end_pos.y ) then
ground_level = start_pos.y ;
end
local cid_air = minetest.get_content_id ( " air " ) ;
for y = ground_level + 1 , end_pos.y do
for x = start_pos.x , end_pos.x do
for z = start_pos.z , end_pos.z do
data [ a : index ( x , y , z ) ] = cid_air ;
end
end
end
local cid_dirt = minetest.get_content_id ( " default:dirt " ) ;
for y = start_pos.y , ground_level - 1 do
for x = start_pos.x , end_pos.x do
for z = start_pos.z , end_pos.z do
data [ a : index ( x , y , z ) ] = cid_dirt ;
end
end
end
-- store the changed map data
vm : set_data ( data ) ;
vm : write_to_map ( ) ;
vm : update_liquids ( ) ;
vm : update_map ( ) ;
end
2018-01-11 19:02:36 +01:00
-- call on_construct where needed;
-- trees, chests and signs receive no special treatment here
--
-- the function generate_building(..) returns a table that includes the
-- table extra_calls.on_constr; that one is needed as input here and
-- on_construct is called for all the nodes (indices of the table) and
-- positions (stored in an array)
handle_schematics.call_on_construct = function ( extra_calls_on_constr )
if ( not ( extra_calls_on_constr ) ) then
return ;
end
for k , v in pairs ( extra_calls_on_constr ) do
local node_name = minetest.get_name_from_content_id ( k ) ;
local node_def = handle_schematics.node_defined ( node_name ) ;
if ( node_def and node_def.on_construct ) then
for _ , pos in ipairs ( v ) do
node_def.on_construct ( pos ) ;
end
end
end
end
-- the function generate_building(..) returns a table that includes the
-- table extra_calls.door_b; that table includes node names and positions
-- of doors that need further setup regarding metadata and changes in
-- minetest_game over time
handle_schematics.call_door_setup = function ( extra_calls_door_b )
if ( not ( extra_calls_door_b ) ) then
return ;
end
for k , v in pairs ( extra_calls_door_b ) do
local meta = minetest.get_meta ( v ) ;
-- taken from the doors mod in minetest_game
local l = 2 -- b
local h = meta : get_int ( " right " ) + 1
local replace = {
{ { type = " a " , state = 0 } , { type = " a " , state = 3 } } ,
{ { type = " b " , state = 1 } , { type = " b " , state = 2 } }
}
local new = replace [ l ] [ h ]
meta : set_int ( " state " , new.state )
-- wipe meta on top node as it's unused
minetest.set_node ( { x = v.x , y = v.y + 1 , z = v.z } , { name = " doors:hidden " } )
end
end
2015-05-01 18:04:03 +02:00
if ( minetest.get_modpath ( ' moresnow ' ) ) then
handle_schematics.moresnow_installed = true ;
end