1788 lines
74 KiB
Lua
1788 lines
74 KiB
Lua
-----------------------------------------------------------------------------------------------------------------
|
|
-- interface for manual placement of houses
|
|
-----------------------------------------------------------------------------------------------------------------
|
|
|
|
-- 25.12.13 cleaned up namespace
|
|
|
|
-- from random_buildings, these functions/values are used:
|
|
-- random_buildings.building[ building_name ]: menu_path, nodes
|
|
-- random_buildings.spawn_building(..)
|
|
-- random_buildings.build_building(..)
|
|
-- random_buildings.spawn_trader_at_building(..)
|
|
|
|
|
|
-- functions specific to the build_chest are now stored in this table
|
|
build_chest = {};
|
|
|
|
-- scaffolding that will be placed instead of other nodes in order to show
|
|
-- how large the building will be
|
|
build_chest.SUPPORT = 'build_chest:support';
|
|
|
|
|
|
-- contains information about all the buildings
|
|
build_chest.building = {};
|
|
|
|
-- returns the id under which the building is stored
|
|
build_chest.add_building = function( file_name, data )
|
|
if( not( file_name ) or not( data )) then
|
|
return;
|
|
end
|
|
build_chest.building[ file_name ] = data;
|
|
end
|
|
|
|
-- that many options can be shown simultaneously on one menu page
|
|
build_chest.MAX_OPTIONS = 24; -- 3 columns with 8 entries each
|
|
|
|
|
|
build_chest.menu = {};
|
|
build_chest.menu.main = {};
|
|
|
|
-- create a tree structure for the menu
|
|
build_chest.add_entry = function( path )
|
|
if( not( path ) or #path<1 ) then
|
|
return;
|
|
end
|
|
|
|
local sub_menu = build_chest.menu;
|
|
for i,v in ipairs( path ) do
|
|
if( not( sub_menu[ v ] )) then
|
|
sub_menu[ v ] = {};
|
|
end
|
|
sub_menu = sub_menu[ v ];
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- helper function; sorts by the second element of the table
|
|
local function build_chest_comp(a,b)
|
|
if (a[2] > b[2]) then
|
|
return true;
|
|
end
|
|
end
|
|
|
|
-- create a statistic about how frequent each node name occoured
|
|
build_chest.count_nodes = function( data )
|
|
local statistic = {};
|
|
for z = 1, data.size.z do
|
|
for y = 1, data.size.y do
|
|
for x = 1, data.size.x do
|
|
|
|
local a = data.scm_data_cache[y][x][z];
|
|
local id = 0;
|
|
if( type( a )=='table' ) then
|
|
id = a[1];
|
|
else
|
|
id = a;
|
|
end
|
|
if( not( statistic[ id ] )) then
|
|
statistic[ id ] = { id, 1};
|
|
else
|
|
statistic[ id ] = { id, statistic[ id ][ 2 ]+1 };
|
|
end
|
|
end
|
|
end
|
|
end
|
|
table.sort( statistic, build_chest_comp );
|
|
return statistic;
|
|
end
|
|
|
|
|
|
-- creates a 2d preview image (or rather, the data structure for it) of the building
|
|
build_chest.create_preview_image = function( data )
|
|
local preview = {};
|
|
for y = 1, data.size.y do
|
|
preview[ y ] = {};
|
|
for z = 1, data.size.z do
|
|
local found = nil;
|
|
local x = 1;
|
|
while( not( found ) and x<= data.size.x ) do
|
|
local node = data.scm_data_cache[y][x][z];
|
|
if( node
|
|
and data.nodenames[ node ]
|
|
and data.nodenames[ node ] ~= 'air'
|
|
and data.nodenames[ node ] ~= 'ignore'
|
|
and data.nodenames[ node ] ~= 'mg:ignore' ) then
|
|
-- a preview node is only set if there's no air there
|
|
preview[y][z] = node;
|
|
end
|
|
x = x+1;
|
|
end
|
|
end
|
|
end
|
|
return preview;
|
|
end
|
|
|
|
|
|
build_chest.read_building = function( building_name )
|
|
-- read data
|
|
local res = handle_schematics.analyze_mts_file( building_name );
|
|
build_chest.building[ building_name ].size = res.size;
|
|
build_chest.building[ building_name ].nodenames = res.nodenames;
|
|
build_chest.building[ building_name ].rotated = res.rotated;
|
|
build_chest.building[ building_name ].burried = res.burried;
|
|
-- scm_data_cache is not stored as that would take up too much storage space
|
|
--build_chest.building[ building_name ].scm_data_cache = res.scm_data_cache;
|
|
|
|
-- create a statistic about how often each node occours
|
|
build_chest.building[ building_name ].statistic = build_chest.count_nodes( res );
|
|
|
|
-- create a 2d overview image (or rather, the data structure for it)
|
|
build_chest.building[ building_name ].preview = build_chest.create_preview_image( res );
|
|
end
|
|
|
|
|
|
build_chest.get_replacement_list_formspec = function( pos, selected_row )
|
|
if( not( pos )) then
|
|
return "";
|
|
end
|
|
local meta = minetest.env:get_meta( pos );
|
|
local replacements = minetest.deserialize( meta:get_string( 'replacements' ));
|
|
local building_name = meta:get_string( 'building_name' );
|
|
if( not( building_name ) or not( build_chest.building[ building_name ])) then
|
|
return "";
|
|
end
|
|
local replace_row = meta:get_int('replace_row');
|
|
|
|
local formspec = "tableoptions[" ..
|
|
"color=#ff8000;" ..
|
|
"background=#0368;" ..
|
|
"border=true;" ..
|
|
--"highlight=#00008040;" ..
|
|
"highlight=#aaaaaaaa;" ..
|
|
"highlight_text=#7fffff]" ..
|
|
"tablecolumns[" ..
|
|
"color;" ..
|
|
"text,width=1,align=right;" ..
|
|
"color;" ..
|
|
"text,width=5;" ..
|
|
"color;" ..
|
|
"text,width=1;" ..
|
|
"color;" ..
|
|
"text,width=5]" ..
|
|
-- "tabheader["..
|
|
-- "1,1;columns;amount,original material,,target material;1;true;true]"..
|
|
"table["..
|
|
"0.5,2.7;9.4,6.8;build_chest_replacements;";
|
|
|
|
local j=1;
|
|
local may_proceed = true;
|
|
local replace_row_material = nil;
|
|
local replace_row_with = "";
|
|
-- make sure the statistic has been created
|
|
if( not( build_chest.building[ building_name ].statistic )) then
|
|
build_chest.read_building( building_name );
|
|
end
|
|
for i,v in ipairs( build_chest.building[ building_name ].statistic ) do
|
|
local name = build_chest.building[ building_name ].nodenames[ v[1]];
|
|
-- nodes that are to be ignored do not need to be replaced
|
|
if( name ~= 'air' and name ~= 'ignore' and name ~= 'mg:ignore' ) then
|
|
local anz = v[2];
|
|
-- find out if this node name gets replaced
|
|
local repl = name;
|
|
for j,r in ipairs( replacements ) do
|
|
if( r and r[1]==name ) then
|
|
repl = r[2];
|
|
end
|
|
end
|
|
|
|
formspec = formspec..'#fff,'..tostring( anz )..',';
|
|
if( name == repl and repl and minetest.registered_nodes[ repl ]) then
|
|
formspec = formspec.."#0ff,,#fff,,";
|
|
else
|
|
if( name and minetest.registered_nodes[ name ] ) then
|
|
formspec = formspec.."#0f0,"; -- green
|
|
else
|
|
formspec = formspec.."#ff0,"; -- yellow
|
|
end
|
|
formspec = formspec..name..',#fff,'..minetest.formspec_escape('-->')..',';
|
|
end
|
|
|
|
if( repl and (minetest.registered_nodes[ repl ] or repl=='air') ) then
|
|
formspec = formspec.."#0f0,"..repl; -- green
|
|
else
|
|
formspec = formspec.."#ff0,?"; -- yellow
|
|
may_proceed = false; -- we need a replacement for this material
|
|
end
|
|
|
|
if( i<#build_chest.building[ building_name ].statistic ) then
|
|
formspec = formspec..",";
|
|
end
|
|
|
|
if( j == replace_row ) then
|
|
replace_row_material = name;
|
|
if( repl ~= name ) then
|
|
replace_row_with = repl;
|
|
end
|
|
end
|
|
j=j+1;
|
|
end
|
|
end
|
|
formspec = formspec.."]";
|
|
-- add the proceed-button as soon as all unkown materials have been replaced
|
|
if( may_proceed ) then
|
|
formspec = formspec.."button[9.9,9.0;2.0,0.5;proceed_with_scaffolding;Proceed]";
|
|
end
|
|
if( replace_row_material ) then
|
|
formspec = formspec..
|
|
"label[0.5,2.1;Replace "..
|
|
minetest.formspec_escape( replace_row_material ).."]"..
|
|
"label[6.5,2.1;with:]"..
|
|
"field[7.5,2.4;4,0.5;replace_row_with;;"..
|
|
minetest.formspec_escape( replace_row_with ).."]"..
|
|
"field[-10,-10;0.1,0.1;replace_row_material;;"..
|
|
minetest.formspec_escape( replace_row_material ).."]"..
|
|
"button[11.1,2.1;1,0.5;store_replacement;Store]";
|
|
end
|
|
return formspec;
|
|
end
|
|
|
|
|
|
build_chest.apply_replacement = function( pos, meta, old_material, new_material )
|
|
-- a new value has been entered - we do not need to remember the row any longer
|
|
meta:set_int('replace_row', 0 );
|
|
local found = false;
|
|
-- only accept replacements which can actually be placed
|
|
if( new_material=='air' or minetest.registered_nodes[ new_material ] ) then
|
|
local replacements_orig = minetest.deserialize( meta:get_string( 'replacements' ));
|
|
for i,v in ipairs(replacements_orig) do
|
|
if( v and v[1]==old_material ) then
|
|
v[2] = new_material;
|
|
found = true;
|
|
end
|
|
end
|
|
if( not( found )) then
|
|
table.insert( replacements_orig, { old_material, new_material });
|
|
end
|
|
-- store the new set of replacements
|
|
meta:set_string( 'replacements', minetest.serialize( replacements_orig ));
|
|
end
|
|
end
|
|
|
|
|
|
-- this function makes sure that the building will always extend to the right and in front of the build chest
|
|
handle_schematics.translate_param2_to_rotation = function( param2, mirror, start_pos, orig_max, rotated, burried, orients )
|
|
|
|
-- mg_villages stores available rotations of buildings in orients={0,1,2,3] format
|
|
if( orients and #orients and orients[1]~=0) then
|
|
if( orients[1]==1 ) then
|
|
rotated = rotated + 90;
|
|
elseif( orients[1]==2 ) then
|
|
rotated = rotated + 180;
|
|
elseif( orients[1]==3 ) then
|
|
rotated = rotated + 270;
|
|
end
|
|
if( rotated > 360 ) then
|
|
rotated = rotated % 360;
|
|
end
|
|
end
|
|
|
|
local max = {x=orig_max.x, y=orig_max.y, z=orig_max.z};
|
|
-- if the schematic has been saved in a rotated way, swapping x and z may be necessary
|
|
if( rotated==90 or rotated==270) then
|
|
max.x = orig_max.z;
|
|
max.z = orig_max.x;
|
|
end
|
|
|
|
-- the building may have a cellar or something alike
|
|
if( burried > 0 ) then
|
|
start_pos.y = start_pos.y - burried;
|
|
end
|
|
|
|
-- make sure the building always extends forward and to the right of the player
|
|
local rotate = 0;
|
|
if( param2 == 0 ) then rotate = 270; if( mirror==1 ) then start_pos.x = start_pos.x - max.x + max.z; end -- z gets larger
|
|
elseif( param2 == 1 ) then rotate = 0; start_pos.z = start_pos.z - max.z; -- x gets larger
|
|
elseif( param2 == 2 ) then rotate = 90; start_pos.z = start_pos.z - max.x;
|
|
if( mirror==0 ) then start_pos.x = start_pos.x - max.z; -- z gets smaller
|
|
else start_pos.x = start_pos.x - max.x; end
|
|
elseif( param2 == 3 ) then rotate = 180; start_pos.x = start_pos.x - max.x; -- x gets smaller
|
|
end
|
|
|
|
if( param2 == 1 or param2 == 0) then
|
|
start_pos.z = start_pos.z + 1;
|
|
elseif( param2 == 1 or param2 == 2 ) then
|
|
start_pos.x = start_pos.x + 1;
|
|
end
|
|
if( param2 == 1 ) then
|
|
start_pos.x = start_pos.x + 1;
|
|
end
|
|
|
|
rotate = rotate + rotated;
|
|
-- make sure the rotation does not reach or exceed 360 degree
|
|
if( rotate >= 360 ) then
|
|
rotate = rotate - 360;
|
|
end
|
|
-- rotate dimensions when needed
|
|
if( param2==0 or param2==2) then
|
|
local tmp = max.x;
|
|
max.x = max.z;
|
|
max.z = tmp;
|
|
end
|
|
|
|
return { rotate=rotate, start_pos = {x=start_pos.x, y=start_pos.y, z=start_pos.z},
|
|
end_pos = {x=(start_pos.x+max.x-1), y=(start_pos.y+max.y-1), z=(start_pos.z+max.z-1) },
|
|
max = {x=max.x, y=max.y, z=max.z}};
|
|
end
|
|
|
|
|
|
|
|
build_chest.get_start_pos = function( pos )
|
|
-- rotate the building so that it faces the player
|
|
local node = minetest.env:get_node( pos );
|
|
local meta = minetest.env:get_meta( pos );
|
|
|
|
local building_name = meta:get_string( 'building_name' );
|
|
if( not( building_name )) then
|
|
return;
|
|
end
|
|
if( not( build_chest.building[ building_name ] )) then
|
|
return;
|
|
end
|
|
|
|
if( not( build_chest.building[ building_name ].size )) then
|
|
build_chest.read_building( building_name );
|
|
end
|
|
local selected_building = build_chest.building[ building_name ];
|
|
|
|
local mirror = 0; -- place_schematic does not support mirroring
|
|
|
|
local start_pos = {x=pos.x, y=pos.y, z=pos.z};
|
|
-- yoff(set) from mg_villages (manually given)
|
|
if( selected_building.yoff ) then
|
|
start_pos.y = start_pos.y + selected_building.yoff -1;
|
|
end
|
|
|
|
-- make sure the building always extends forward and to the right of the player
|
|
local param2_rotated = handle_schematics.translate_param2_to_rotation( node.param2, mirror, start_pos,
|
|
selected_building.size, selected_building.rotated, selected_building.burried, selected_building.orients );
|
|
|
|
-- save the data for later removal/improvement of the building in the chest
|
|
meta:set_string( 'start_pos', minetest.serialize( param2_rotated.start_pos ));
|
|
meta:set_string( 'end_pos', minetest.serialize( param2_rotated.end_pos ));
|
|
meta:set_string( 'rotate', tostring(param2_rotated.rotate ));
|
|
meta:set_int( 'mirror', mirror );
|
|
-- no replacements yet
|
|
meta:set_string( 'replacements', minetest.serialize( {} ));
|
|
return start_pos;
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- -- TODO: some nodes are double ones - i.e. doors
|
|
-- -- TODO: given how much air there is, probably do not store air at all?
|
|
-- -- TODO: stairs:stair_woodupside_down and its coutnerpart - slabs - are in effect the same as well...
|
|
|
|
|
|
|
|
-- building consists of several steps:
|
|
-- 0. cobble, tree
|
|
-- 1. wood, loam, everything else that doesn't fit elsewhere
|
|
-- 2. straw (for roof)
|
|
-- 3. window shutters, doors, halfdoors, gates
|
|
-- 4. straw mat, steel hoe, bucket water/lava
|
|
-- 5. furniture
|
|
-- 6. bed and decoration
|
|
build_chest.update_needed_list = function( pos, step )
|
|
|
|
local meta = minetest.env:get_meta( pos );
|
|
local inv = meta:get_inventory();
|
|
local building_name = meta:get_string( 'building_name' );
|
|
local material_type = meta:get_string( 'material_type');
|
|
|
|
local menu_path = build_chest.building[ building_name ].menu_path;
|
|
|
|
-- at the beginning, *each* node is replaced by a scaffolding-like support structure
|
|
local replacements = {};
|
|
local node_needed_list = {};
|
|
for k,v in pairs( build_chest.building[ building_name ].nodes ) do
|
|
replacements[ v.node ] = build_chest.SUPPORT;
|
|
|
|
local node_needed = v.node; -- name of the node we are working on
|
|
local anz = #v.posx; -- how many of that type do we need?
|
|
local needed_in_step = 1; -- building works in steps: basic materials (wood, straw, cobble, ..); doors, fences etc; hoe+water; furniture
|
|
|
|
-- the workers supply the building with free dirt
|
|
if( v.node == 'default:dirt'
|
|
or v.node == 'default:dirt_with_grass'
|
|
-- ignore the upper parts of doors
|
|
or v.node == 'doors:door_wood_t_1'
|
|
or v.node == 'doors:door_wood_t_2' ) then
|
|
|
|
anz = 0;
|
|
needed_in_step = 0;
|
|
-- the lower part of the door counts as one door
|
|
elseif( v.node == 'doors:door_wood_b_1'
|
|
or v.node == 'doors:door_wood_b_2' ) then
|
|
|
|
node_needed = 'doors:door_wood';
|
|
needed_in_step = 3; -- after the basic frame has been built
|
|
|
|
elseif( v.node == 'cottages:half_door'
|
|
or v.node == 'cottages:half_door_inverted' ) then
|
|
|
|
needed_in_step = 3;
|
|
node_needed = 'cottages:half_door';
|
|
|
|
elseif( v.node == 'cottages:gate_open'
|
|
or v.node == 'cottages:gate_closed' ) then
|
|
|
|
needed_in_step = 3;
|
|
node_needed = 'cottages:gate_closed';
|
|
|
|
elseif( v.node == 'cottages:window_shutter_open'
|
|
or v.node == 'cottages:window_shutter_closed' ) then
|
|
|
|
needed_in_step = 3;
|
|
node_needed = 'cottages:window_shutter_closed';
|
|
|
|
-- TODO: in general: require what the nodes gives when the player digs it (that ought to cover doors)
|
|
-- (at least as long as it's a single drop)
|
|
|
|
--
|
|
-- lumberjacks bring their own wood (provided they get an axe!)
|
|
--
|
|
elseif( menu_path[2]=='lumberjack'
|
|
-- TODO: node names may have to be adjusted once this is switched to blueprints
|
|
and (v.node == 'moretrees:TYP_planks'
|
|
or v.node == 'moretrees:TYP_trunk'
|
|
or v.node == 'moretrees:TYP_trunk_sideways'
|
|
or v.node == 'moretrees:slab_TYP_planks'
|
|
-- they also build their own roofs
|
|
or v.node == 'cottages:roof_wood'
|
|
or v.node == 'cottages:roof_connector_wood'
|
|
or v.node == 'cottages:roof_flat_wood' )) then
|
|
|
|
anz = 1;
|
|
needed_in_step = 1;
|
|
-- lumberjacks love mese picks and use them to get wood
|
|
node_needed = 'default:axe_mese';
|
|
|
|
|
|
|
|
--
|
|
-- clay traders dig clay, sandstone and sandstonebricks on their own
|
|
--
|
|
elseif( menu_path[2]=='clay'
|
|
and (v.node == 'default:clay'
|
|
or v.node == 'default:sand'
|
|
or v.node == 'default:desert_sand'
|
|
or v.node == 'default:sandstone'
|
|
or v.node == 'default:sandstonebrick'
|
|
|
|
or v.node == 'stairs:slab_sandstone'
|
|
or v.node == 'stairs:slab_sandstonebrick')) then
|
|
|
|
anz = 1;
|
|
needed_in_step = 1;
|
|
-- clay traders dig their own clay and sandstone
|
|
node_needed = 'default:shovel_mese';
|
|
|
|
--
|
|
-- clay traders know how to use furnaces on sand and clay lumps
|
|
--
|
|
elseif( menu_path[2]=='clay'
|
|
and (v.node == 'default:brick'
|
|
or v.node == 'default:glass'
|
|
or v.node == 'stairs:slab_brick'
|
|
or v.node == 'stairs:slab_glass')) then
|
|
|
|
anz = 1;
|
|
needed_in_steP = 1;
|
|
-- clay traders produce their own brick and glass
|
|
node_needed = 'default:furnace';
|
|
-- one furnace is sufficient for production
|
|
if( node_needed_list[ node_needed ] and node_needed_list[ node_needed ] > 0 ) then
|
|
anz = 0;
|
|
end
|
|
|
|
|
|
--
|
|
-- farmers produce farmland and grow plants; they also bring their own straw for roofs
|
|
--
|
|
elseif( menu_path[2]=='small_farm'
|
|
and (v.node == 'farming:soil'
|
|
or v.node == 'farming:soil_wet'
|
|
or v.node == 'farming:cotton'
|
|
or v.node == 'farming:cotton_1'
|
|
or v.node == 'farming:cotton_2'
|
|
or v.node == 'farming:cotton_3' )) then
|
|
|
|
-- TODO: more suitable for large farms
|
|
-- or v.node == 'cottages:roof'
|
|
-- or v.node == 'cottages:roof_connector'
|
|
-- or v.node == 'cottages:roof_flat'
|
|
-- or v.node == 'cottages:roof_straw'
|
|
-- or v.node == 'cottages:roof_connector_straw'
|
|
-- or v.node == 'cottages:roof_flat_straw' )) then
|
|
|
|
anz = 1;
|
|
node_needed = 'farming:hoe_steel';
|
|
needed_in_step = 4; -- step4: hoe + water
|
|
-- one hoe is sufficient
|
|
if( node_needed_list[ node_needed ] and node_needed_list[ node_needed ] > 0 ) then
|
|
anz = 0;
|
|
end
|
|
|
|
|
|
-- water comes in buckets; one is enough (they can refill it...in theory)
|
|
elseif( v.node == 'default:water_source' ) then
|
|
anz = 1;
|
|
node_needed = 'bucket:bucket_water';
|
|
needed_in_step = 4; -- step4: hoe + water
|
|
if( node_needed_list[ node_needed ] and node_needed_list[ node_needed ] > 0 ) then
|
|
anz = 0;
|
|
end
|
|
-- same with lava
|
|
elseif( v.node == 'default:lava_source' ) then
|
|
anz = 1;
|
|
node_needed = 'bucket:bucket_lava';
|
|
needed_in_step = 4; -- step4: hoe + water (well, ok, and lava)
|
|
if( node_needed_list[ node_needed ] and node_needed_list[ node_needed ] > 0 ) then
|
|
anz = 0;
|
|
end
|
|
|
|
-- those nodes can not be placed
|
|
elseif( v.node == 'default:water_flowing'
|
|
or v.node == 'default:lava_flowing' ) then
|
|
anz = 0;
|
|
|
|
-- in the farm_tiny_?.we buildings, sandstone is used for the floor, and clay for the lower walls
|
|
elseif( v.node == 'default:sandstone'
|
|
or v.node == 'default:clay'
|
|
or v.node == 'cottages:straw_ground' ) then
|
|
node_needed = 'cottages:loam';
|
|
needed_in_step = 1;
|
|
|
|
-- for the various roof parts, we need straw; the roof can later be upgraded
|
|
elseif( v.node == 'cottages:roof'
|
|
or v.node == 'cottages:roof_connector'
|
|
or v.node == 'cottages:roof_flat'
|
|
or v.node == 'cottages:roof_straw'
|
|
or v.node == 'cottages:roof_connector_straw'
|
|
or v.node == 'cottages:roof_flat_straw' ) then
|
|
|
|
anz = math.ceil( anz/3 ); -- one straw bale can be turned into several roof parts
|
|
node_needed = 'cottages:straw_bale';
|
|
needed_in_step = 2;
|
|
|
|
|
|
-- do not add this before the walls are standing...
|
|
elseif( v.node == 'default:torch' ) then
|
|
needed_in_step = 5;
|
|
|
|
-- these chests are diffrent so that they can be filled differently by fill_chests.lua
|
|
-- chests count as furniture and are added in the second step
|
|
elseif( v.node == 'cottages:chest_private'
|
|
or v.node == 'cottages:chest_work'
|
|
or v.node == 'cottages:chest_storage'
|
|
or v.node == 'default:chest' ) then
|
|
node_needed = 'default:chest';
|
|
needed_in_step = 5;
|
|
|
|
-- furniture and outside decoration is nothing the future inhabitant needs immediately; it can be supplied after moving in
|
|
elseif( v.node == 'cottages:bench'
|
|
or v.node == 'cottages:table'
|
|
or v.node == 'cottages:shelf'
|
|
or v.node == 'cottages:washing'
|
|
or v.node == 'cottages:wagon_wheel'
|
|
or v.node == 'cottages:tub' ) then
|
|
needed_in_step = 6;
|
|
|
|
elseif( v.node == 'cottages:barrel'
|
|
or v.node == 'cottages:barrel_open'
|
|
or v.node == 'cottages:barrel_lying'
|
|
or v.node == 'cottages:barrel_lying_open' ) then
|
|
node_needed = 'cottages:barrel';
|
|
needed_in_step = 6;
|
|
|
|
-- at first, a simple straw mat is enough for the NPC to sleep on - and that can be created from straw
|
|
-- changed so that the bed is built immediately
|
|
elseif( v.node == 'cottages:bed_head'
|
|
or v.node == 'cottages:bed_foot'
|
|
or v.node == 'cottages:sleeping_mat'
|
|
or v.node == 'cottages:straw_mat' ) then
|
|
|
|
if( v.node=='cottages:straw_mat') then -- or step == 4) then
|
|
node_needed = 'cottages:straw_mat';
|
|
replacements[ 'cottages:bed_head' ] = 'cottages:staw_mat';
|
|
replacements[ 'cottages:bed_foot' ] = 'cottages:staw_mat';
|
|
replacements[ 'cottages:sleeping_mat'] = 'cottages:staw_mat';
|
|
replacements[ 'cottages:straw_mat' ] = 'cottages:staw_mat';
|
|
needed_in_step = 4;
|
|
elseif( v.node == 'cottages:sleeping_mat') then -- or step == 5 ) then
|
|
node_needed = 'cottages:sleeping_mat';
|
|
replacements[ 'cottages:bed_head' ] = 'cottages:sleeping_mat';
|
|
replacements[ 'cottages:bed_foot' ] = 'cottages:sleeping_mat';
|
|
replacements[ 'cottages:sleeping_mat'] = 'cottages:sleeping_mat';
|
|
needed_in_step = 5;
|
|
elseif( true ) then -- and step == 6 ) then
|
|
node_needed = v.node;
|
|
replacements[ 'cottages:bed_head' ] = 'cottages:bed_head';
|
|
replacements[ 'cottages:bed_foot' ] = 'cottages:bed_foot';
|
|
needed_in_step = 6;
|
|
else
|
|
anz = 0;
|
|
end
|
|
|
|
-- a basic house has fence posts as windows; glass panes are a later upgrade
|
|
elseif( v.node == 'cottages:glass_pane'
|
|
or v.node == 'default:fence_wood' ) then
|
|
node_needed = 'default:fence_wood';
|
|
needed_in_step = 2;
|
|
|
|
-- wooden slabs and stairs are crafted automaticly
|
|
elseif( v.node == 'stairs:slab_wood'
|
|
or v.node == 'stairs:stair_wood'
|
|
or v.node == 'stairs:slab_woodupside_down' ) then
|
|
|
|
anz = math.ceil( anz/2 ); -- stairs are thus minimally cheaper
|
|
node_needed = 'default:wood';
|
|
needed_in_step = 1;
|
|
|
|
-- same with cobble: cobble slabs and stairs are crafted automaticly
|
|
elseif( v.node == 'stairs:slab_cobble'
|
|
or v.node == 'stairs:stair_cobble'
|
|
or v.node == 'stairs:slab_cobbleupside_down' ) then
|
|
|
|
anz = math.ceil( anz/2 ); -- stairs are thus minimally cheaper
|
|
node_needed = 'default:cobble';
|
|
needed_in_step = 0;
|
|
|
|
elseif( v.node == 'default:cobble'
|
|
or v.node == 'default:tree' ) then
|
|
needed_in_step = 0;
|
|
end
|
|
-- TODO: replace default:tree and default:wood with the local wood the village is specialized on?
|
|
-- TODO: combine bed_foot and bed_head into one to save space?
|
|
|
|
-- it is better if these buildings request all materials in one step (they produce most material by themshelves)
|
|
if(( menu_path[2]=='lumberjack'
|
|
or menu_path[2]=='clay'
|
|
or menu_path[2]=='small_farm' )
|
|
and needed_in_step > 1 ) then
|
|
needed_in_step = 2;
|
|
end
|
|
-- list the items as needed in the suitable fields
|
|
if( anz > 0 and needed_in_step == step) then
|
|
|
|
-- avoid new stacks for nodes with diffrent facedir
|
|
if( not(node_needed_list[ node_needed ] )) then
|
|
node_needed_list[ node_needed ] = anz;
|
|
else
|
|
node_needed_list[ node_needed ] = node_needed_list[ node_needed ] + anz;
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
-- insert full stacks into the list of needed things
|
|
for k, v in pairs(node_needed_list) do
|
|
inv:add_item("needed", k.." "..node_needed_list[ k ]);
|
|
--print(' adding needed items: '..tostring( k.." "..node_needed_list[ k ] ));
|
|
end
|
|
|
|
meta:set_int( 'building_stage', step );
|
|
|
|
-- if in this step nothing is needed, move to the next step
|
|
if( inv:is_empty( 'needed') and step < 6 and (#node_needed_list==0)) then
|
|
return build_chest.update_needed_list( pos, step+1 );
|
|
end
|
|
|
|
return replacements;
|
|
end
|
|
|
|
|
|
|
|
-- built support platform and scaffholding where building will be built
|
|
build_chest.build_scaffolding = function( pos, player, building_name )
|
|
|
|
local name = player:get_player_name();
|
|
|
|
-- rotate the building so that it faces the player
|
|
local node = minetest.env:get_node( pos );
|
|
local meta = minetest.env:get_meta( pos );
|
|
local inv = meta:get_inventory();
|
|
|
|
local start_pos = {x=pos.x, y=pos.y, z=pos.z};
|
|
|
|
local mirror = math.random(0,1); -- TODO
|
|
|
|
local selected_building = build_chest.building[ building_name ];
|
|
|
|
local max = { x = selected_building.max.x, y = selected_building.max.y, z = selected_building.max.z };
|
|
-- local min = { x = selected_building.min.x, y = selected_building.min.y, z = selected_building.min.z };
|
|
|
|
-- make sure the building always extends forward and to the right of the player
|
|
local rotate = 0;
|
|
if( node.param2 == 0 ) then rotate = 3; if( mirror==1 ) then start_pos.x = start_pos.x - max.x + max.z; end -- z gets larger
|
|
elseif( node.param2 == 1 ) then rotate = 0; start_pos.z = start_pos.z - max.z; -- x gets larger
|
|
elseif( node.param2 == 2 ) then rotate = 1; start_pos.z = start_pos.z - max.x;
|
|
if( mirror==0 ) then start_pos.x = start_pos.x - max.z; -- z gets smaller
|
|
else start_pos.x = start_pos.x - max.x; end
|
|
elseif( node.param2 == 3 ) then rotate = 2; start_pos.x = start_pos.x - max.x; -- x gets smaller
|
|
end
|
|
|
|
|
|
-- the chest becomes part of the building
|
|
if( node.param2 == 0 ) then start_pos.z = start_pos.z - 1;
|
|
elseif( node.param2 == 1 ) then start_pos.x = start_pos.x - 1;
|
|
elseif( node.param2 == 2 ) then start_pos.z = start_pos.z + 1;
|
|
elseif( node.param2 == 3 ) then start_pos.x = start_pos.x + 1;
|
|
end
|
|
|
|
minetest.chat_send_player( name, "Facedir: "..minetest.serialize( node.param2 ).." rotate: "..tostring( rotate ).." mirror: "..tostring( mirror));
|
|
|
|
local replacements = build_chest.update_needed_list( pos, 0 ); -- request the material for the very first building step
|
|
|
|
-- default replacements that will always be supplied
|
|
-- the inhabitants have enough dirt to spare
|
|
replacements[ 'default:dirt' ] = 'default:dirt';
|
|
replacements[ 'default:dirt_with_grass' ] = 'default:dirt';
|
|
-- soil has not been worked on yet and thus is just dirt
|
|
replacements[ 'farming:soil' ] = 'default:dirt';
|
|
replacements[ 'farming:soil_wet' ] = 'default:dirt';
|
|
-- weed can be made to grow everywhere..so why not on dirt
|
|
replacements[ 'farming:cotton' ] = 'farming:weed';
|
|
replacements[ 'farming:cotton_1' ] = 'farming:weed';
|
|
replacements[ 'farming:cotton_2' ] = 'farming:weed';
|
|
|
|
--print( 'nodes: '..minetest.serialize( build_chest.building[ building_name ].nodes ))
|
|
--print( 'replacements: '..minetest.serialize( replacements ));
|
|
|
|
-- so that the building with its possible platform does not end up too high
|
|
--start_pos.y = start_pos.y - 1;
|
|
-- save the data for later removal/improvement of the building in the chest
|
|
meta:set_string( 'start_pos', minetest.serialize( start_pos ) );
|
|
-- building_name has already been saved
|
|
meta:set_int( 'rotate', rotate );
|
|
meta:set_int( 'mirror', mirror );
|
|
meta:set_string( 'replacements', minetest.serialize( replacements ));
|
|
print('SETTING replacements IN build_scaffolding');
|
|
-- the replacements are not yet of much intrest
|
|
local result = random_buildings.spawn_building( start_pos, building_name, rotate, mirror, replacements, nil, pos); -- do not spawn an inhabitant yet
|
|
-- in case spawn_building decided to place the building higher
|
|
meta:set_string( 'start_pos', minetest.serialize( {x=result.x, y=result.y, z=result.z}) );
|
|
|
|
if( result.status == 'aborted' ) then
|
|
minetest.chat_send_player(name, "Could not build here! Reason: "..tostring( result.reason or 'unknown'));
|
|
elseif( result.status == 'need_to_wait' ) then
|
|
minetest.chat_send_player(name, "The terrain has not been generated/loaded completely. Please wait a moment and try again!");
|
|
elseif( result.status ~= 'ok' ) then
|
|
minetest.chat_send_player(name, "Error: Could not build. Status: "..tostring( result.reason or 'unknown' ));
|
|
else
|
|
minetest.chat_send_player(name, "Building of scaffolding for building finished. Status: "..minetest.serialize( result ));
|
|
end
|
|
|
|
return result;
|
|
end
|
|
|
|
|
|
build_chest.update_formspec = function( pos, page, player )
|
|
|
|
local meta = minetest.env:get_meta( pos );
|
|
local current_path = minetest.deserialize( meta:get_string( 'current_path' ) or 'return {}' );
|
|
local page_nr = meta:get_int( 'page_nr' );
|
|
local material_type = meta:get_string( 'material_type');
|
|
local village_name = meta:get_string( 'village' );
|
|
local village_pos = minetest.deserialize( meta:get_string( 'village_pos' ));
|
|
local owner_name = meta:get_string( 'owner' );
|
|
|
|
-- distance from village center
|
|
local distance = math.floor( math.sqrt( (village_pos.x - pos.x ) * (village_pos.x - pos.x )
|
|
+ (village_pos.y - pos.y ) * (village_pos.x - pos.y )
|
|
+ (village_pos.z - pos.z ) * (village_pos.x - pos.z ) ));
|
|
|
|
local button_back = '';
|
|
if( #current_path > 0 ) then
|
|
button_back = "button[9.9,0.4;2,0.5;back;Back]";
|
|
end
|
|
local depth = #current_path;
|
|
local formspec = "size[12,10]"..
|
|
"label[3.3,0.0;Building box]"..button_back.. -- - "..table.concat( current_path, ' -> ').."]"..
|
|
"label[0.3,0.4;Located at:]" .."label[3.3,0.4;"..(minetest.pos_to_string( pos ) or '?')..", which is "..tostring( distance ).." m away]"
|
|
.."label[7.3,0.4;from the village center]"..
|
|
"label[0.3,0.8;Part of village:]" .."label[3.3,0.8;"..(village_name or "?").."]"
|
|
.."label[7.3,0.8;located at "..(minetest.pos_to_string( village_pos ) or '?').."]"..
|
|
"label[0.3,1.2;Owned by:]" .."label[3.3,1.2;"..(owner_name or "?").."]"..
|
|
"label[3.3,1.6;Click on a menu entry to select it:]";
|
|
|
|
|
|
if( page == 'main') then
|
|
|
|
local building_name = meta:get_string('building_name' );
|
|
local start_pos = meta:get_string('start_pos');
|
|
|
|
local backup_file = meta:get_string('backup');
|
|
if( backup_file and backup_file ~= "" ) then
|
|
formspec = formspec.."button[3,3;3,0.5;restore_backup;Restore original landscape]";
|
|
meta:set_string('formspec', formspec );
|
|
return;
|
|
end
|
|
|
|
|
|
if( building_name and building_name ~= '' and start_pos and start_pos ~= '' and meta:get_string('replacements')) then
|
|
formspec = formspec..build_chest.get_replacement_list_formspec( pos );
|
|
meta:set_string('formspec', formspec );
|
|
return;
|
|
end
|
|
|
|
-- find out where we currently are in the menu tree
|
|
local menu = build_chest.menu;
|
|
for i,v in ipairs( current_path ) do
|
|
if( menu and menu[ v ] ) then
|
|
menu = menu[ v ];
|
|
end
|
|
end
|
|
|
|
-- all submenu points at this menu position are options that need to be shown
|
|
local options = {};
|
|
for k,v in pairs( menu ) do
|
|
table.insert( options, k );
|
|
end
|
|
|
|
if( #options == 1 and options[1] and build_chest.building[ options[1]] ) then
|
|
-- a building has been selected
|
|
meta:set_string( 'building_name', options[1] );
|
|
local start_pos = build_chest.get_start_pos( pos );
|
|
if( start_pos and start_pos.x ) then
|
|
-- TODO: also show size and such
|
|
formspec = formspec..build_chest.get_replacement_list_formspec( pos );
|
|
meta:set_string('formspec', formspec );
|
|
-- TODO minetest.place_schematic( start_pos, options[1]..'.mts', meta:get_string('rotate'), meta:get_string('replacements'), true );
|
|
return;
|
|
end
|
|
meta:set_string( 'selected_building', "" );
|
|
end
|
|
table.sort( options );
|
|
|
|
-- if the options do not fit on a single page, split them up
|
|
if( #options > build_chest.MAX_OPTIONS ) then
|
|
if( not( page_nr )) then
|
|
page_nr = 0;
|
|
end
|
|
local new_options = {};
|
|
local new_index = build_chest.MAX_OPTIONS*page_nr;
|
|
for i=1,build_chest.MAX_OPTIONS do
|
|
if( options[ new_index+i ] ) then
|
|
new_options[ i ] = options[ new_index+i ];
|
|
end
|
|
end
|
|
|
|
-- we need to add prev/next buttons to the formspec
|
|
formspec = formspec.."label[7.5,1.5;"..minetest.formspec_escape(
|
|
"Showing "..tostring( new_index+1 )..
|
|
'-'..tostring( math.min( new_index+build_chest.MAX_OPTIONS, #options))..
|
|
'/'..tostring( #options )).."]";
|
|
if( page_nr > 0 ) then
|
|
formspec = formspec.."button[9.5,1.5;1,0.5;prev;prev]";
|
|
end
|
|
if( build_chest.MAX_OPTIONS*(page_nr+1) < #options ) then
|
|
formspec = formspec.."button[11,1.5;1,0.5;next;next]";
|
|
end
|
|
options = new_options;
|
|
end
|
|
|
|
|
|
-- this is not a very efficient way to implement a menu; for this case, it is sufficient
|
|
for k,v in pairs( build_chest.building ) do
|
|
if( k ~= nil and v.menu_path ~= nil and #v.menu_path>0) then
|
|
local found = true;
|
|
|
|
for i,p in ipairs( current_path ) do
|
|
if( i<=(#v.menu_path )) then
|
|
if( v.menu_path[i] ~= p ) then
|
|
found = false;
|
|
end
|
|
end
|
|
end
|
|
|
|
if( found ) then
|
|
if( #v.menu_path > depth ) then
|
|
-- only insert entries we have not found yet
|
|
local f2 = false;
|
|
for j,ign in ipairs( options ) do
|
|
if( ign == v.menu_path[(depth+1)] ) then
|
|
f2 = true;
|
|
end
|
|
end
|
|
-- avoid duplicates
|
|
if( not( f2 )) then
|
|
table.insert( options, v.menu_path[(depth+1)] );
|
|
end
|
|
elseif( (not( material_type ) or material_type == '' ) and v.menu_path[2]=='lumberjack') then
|
|
|
|
-- ask for wood material
|
|
-- default:tree and default:jungletree
|
|
options = { 'normal', 'jungletree' };
|
|
-- trees from moretrees - provided they are enabled
|
|
if( moretrees ) then
|
|
if( moretrees.enable_apple_tree ) then table.insert( options, 'apple tree' ); end
|
|
if( moretrees.enable_oak ) then table.insert( options, 'oak' ); end
|
|
if( moretrees.enable_sequoia ) then table.insert( options, 'sequoia' ); end
|
|
if( moretrees.enable_palm ) then table.insert( options, 'palm' ); end
|
|
if( moretrees.enable_pine ) then table.insert( options, 'pine' ); end
|
|
if( moretrees.enable_rubber_tree) then table.insert( options, 'rubber tree'); end
|
|
if( moretrees.enable_willow ) then table.insert( options, 'willow' ); end
|
|
if( moretrees.enable_birch ) then table.insert( options, 'birch' ); end
|
|
if( moretrees.enable_spruce ) then table.insert( options, 'spruce' ); end
|
|
-- if( moretrees.enable_jungle_tree) then table.insert( options, 'jungletree' ); end
|
|
if( moretrees.enable_fir ) then table.insert( options, 'fir' ); end
|
|
if( moretrees.enable_beech ) then table.insert( options, 'beech' ); end
|
|
end
|
|
|
|
-- TODO:realtest-trees
|
|
if( true ) then
|
|
table.insert( options, 'ash (small)' );
|
|
table.insert( options, 'aspen (small)' );
|
|
table.insert( options, 'birch (small)' );
|
|
table.insert( options, 'maple (small)' );
|
|
table.insert( options, 'chestnut (small)' );
|
|
table.insert( options, 'pine (small)' );
|
|
table.insert( options, 'spruce (small)' );
|
|
end
|
|
|
|
|
|
elseif( (not( material_type ) or material_type == '' ) and v.menu_path[2]=='clay') then
|
|
options = {};
|
|
-- desert_stone and stone would fit optically
|
|
local clay_materials = {'clay','brick','sandstone','sandstonebrick' };
|
|
for i,v in ipairs( clay_materials ) do
|
|
for j,w in ipairs( clay_materials ) do
|
|
table.insert( options, v..' and '..w );
|
|
end
|
|
end
|
|
else
|
|
-- found an end node of the menu graph
|
|
local building_name = v.menu_path[( depth )];
|
|
|
|
if( not( build_chest.building[ building_name ])) then
|
|
minetest.chat_send_player(player:get_player_name(), "ERROR: Building \""..minetest.serialize( building_name ).."\" does not exist!");
|
|
return;
|
|
end
|
|
meta:set_string( 'building_name', building_name );
|
|
|
|
-- set new formspecs for the input materials - this is taken from towntest
|
|
meta:get_inventory():set_size("main", 8)
|
|
meta:get_inventory():set_size("needed", 8*5) -- 2 larger than what is displayed - as a reserve for houses with many diffrent nodes
|
|
meta:get_inventory():set_size("builder", 2*5) -- there are many items he has to carry around
|
|
|
|
local result = build_chest.build_scaffolding( pos, player, building_name );
|
|
if( not( result ) or result.status ~= 'ok' ) then
|
|
meta:set_string( 'current_path', minetest.serialize( {} ));
|
|
meta:set_string( 'building_name', '');
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
return;
|
|
end
|
|
|
|
formspec = "size[12,10]"
|
|
|
|
-- "size[10.5,9]"
|
|
.."list[current_player;main;0,6;8,4;]"
|
|
|
|
.."label[0,0; items needed:]"
|
|
.."list[current_name;needed;0,0.5;8,3;]"
|
|
|
|
.."label[0,3.5; put items here to build:]"
|
|
.."list[current_name;main;0,4;8,1;]"..
|
|
|
|
-- .."label[8.5,1; builder:]"
|
|
-- .."list[current_name;builder;8.5,1.5;2,5;]"..
|
|
|
|
-- .."label[8.5,3.5; lumberjack:]"
|
|
-- .."list[current_name;lumberjack;8.5,4;2,2;]"..
|
|
|
|
"label[8.5,6.0;Project:]" .."label[9.5,6.0;"..(building_name or '?').."]"..
|
|
"label[8.5,6.4;Owner:]" .."label[9.5,6.4;"..(owner_name or "?").."]"..
|
|
"label[8.5,6.8;Village:]" .."label[9.5,6.8;"..(village_name or "?").."]"..
|
|
"label[8.5,7.2;located at]" .."label[9.5,7.2; "..(minetest.pos_to_string( village_pos ) or '?').."]"..
|
|
"label[8.5,7.6;Distance:]" .."label[9.5,7.6;"..tostring( distance ).." m]"..
|
|
|
|
"button[9.0,8.5;2,0.5;abort;Abort building]" .."label[9.5,7.6;"..tostring( distance ).." m]";
|
|
|
|
|
|
meta:set_string( "formspec", formspec );
|
|
return;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local i = 0;
|
|
local x = 0;
|
|
local y = 0;
|
|
if( #options < 9 ) then
|
|
x = x + 4;
|
|
end
|
|
-- order alphabeticly
|
|
table.sort( options, function(a,b) return a < b end );
|
|
|
|
for index,k in ipairs( options ) do
|
|
|
|
i = i+1;
|
|
|
|
-- new column
|
|
if( y==8 ) then
|
|
x = x+4;
|
|
y = 0;
|
|
end
|
|
|
|
formspec = formspec .."button["..(x)..","..(y+2.5)..";4,0.5;selection;"..k.."]"
|
|
y = y+1;
|
|
--x = x+4;
|
|
end
|
|
|
|
elseif( page == 'please_remove' ) then
|
|
local building_name = meta:get_string( 'building_name' );
|
|
formspec = "size[12,10]"
|
|
|
|
-- "size[10.5,9]"
|
|
.."list[current_player;main;0,6;8,4;]"
|
|
|
|
.."label[0,3.5;please remove these items:]"
|
|
.."list[current_name;main;0,4;8,1;]"..
|
|
|
|
"label[8.5,6.0;Project:]" .."label[9.5,6.0;"..(building_name or '?').."]"..
|
|
"label[8.5,6.4;Owner:]" .."label[9.5,6.4;"..(owner_name or "?").."]"..
|
|
"label[8.5,6.8;Village:]" .."label[9.5,6.8;"..(village_name or "?").."]"..
|
|
"label[8.5,7.2;located at]" .."label[9.5,7.2; "..(minetest.pos_to_string( village_pos ) or '?').."]"..
|
|
"label[8.5,7.6;Distance:]" .."label[9.5,7.6;"..tostring( distance ).." m]"..
|
|
|
|
"button[9.0,8.5;2,0.5;abort;Remove building]" .."label[9.5,7.6;"..tostring( distance ).." m]";
|
|
|
|
elseif( page == 'finished' ) then
|
|
|
|
-- when finished, let the NPC move into the building (provided there is one that lives there)
|
|
build_chest.move_trader_in( pos );
|
|
|
|
local building_name = meta:get_string( 'building_name' );
|
|
formspec = "size[12,11]"..
|
|
"label[1,1;Building finished successfully.]"..
|
|
|
|
"button[0.3,2;4,0.5;make_white;paint building white]"..
|
|
"button[0.3,3;4,0.5;make_brick;upgrade to brick]"..
|
|
"button[0.3,4;4,0.5;make_stone;upgrade to stone]"..
|
|
"button[0.3,5;4,0.5;make_cobble;upgrade to cobble]"..
|
|
"button[0.3,6;4,0.5;make_loam;downgrade to loam]"..
|
|
"button[0.3,7;4,0.5;make_wood;turn into wood]"..
|
|
"button[0.3,8;4,0.5;make_junglewood;turn into dark junglewood]"..
|
|
"button[0.3,9;4,0.5;white_and_jungle;bottom white, top junglewood]"..
|
|
"button[0.3,10;4,0.5;white_and_loam;bottom white, top loam]"..
|
|
|
|
"button[4.3,2;4,0.5;roof_straw;turn roof into straw]"..
|
|
"button[4.3,3;4,0.5;roof_tree;turn roof into tree]"..
|
|
"button[4.3,4;4,0.5;roof_black;roof: black (asphalt)]"..
|
|
"button[4.3,5;4,0.5;roof_red;roof: red (terracotta)]"..
|
|
"button[4.3,6;4,0.5;roof_brown;roof: brown (wood)]"..
|
|
|
|
"button[4.3,7;4,0.5;make_glass;upgrade to glass panes]"..
|
|
"button[4.3,8;4,0.5;make_noglass;downgrade to simple windows]"..
|
|
|
|
"button[8.3,2;4,0.5;cobble_cobble;turn cobble into cobble]"..
|
|
"button[8.3,3;4,0.5;cobble_brick;turn cobble into stonebrick]"..
|
|
"button[8.3,4;4,0.5;cobble_stone;turn cobble into stone]"..
|
|
"button[8.3,5;4,0.5;wood_junglewood;turn wood into junglewood]"..
|
|
|
|
"button[8.3,1;4,0.5;wood_wood;turn wood into wood]"..
|
|
|
|
"label[8.5,6.0;Object:]" .."label[9.5,6.0;"..(building_name or '?').."]"..
|
|
"label[8.5,6.4;Owner:]" .."label[9.5,6.4;"..(owner_name or "?").."]"..
|
|
"label[8.5,6.8;Village:]" .."label[9.5,6.8;"..(village_name or "?").."]"..
|
|
"label[8.5,7.2;located at]" .."label[9.5,7.2; "..(minetest.pos_to_string( village_pos ) or '?').."]"..
|
|
"label[8.5,7.6;Distance:]" .."label[9.5,7.6;"..tostring( distance ).." m]"..
|
|
"button[9.0,8.5;2,0.5;abort;Remove building]" .."label[9.5,7.6;"..tostring( distance ).." m]";
|
|
|
|
|
|
end
|
|
|
|
meta:set_string( "formspec", formspec );
|
|
end
|
|
|
|
|
|
build_chest.upgrade_building = function( pos, player, old_material, new_material )
|
|
|
|
local meta = minetest.env:get_meta(pos);
|
|
|
|
local building_name = meta:get_string( 'building_name');
|
|
local start_pos = minetest.deserialize( meta:get_string( 'start_pos' ));
|
|
local rotate = meta:get_int( 'rotate' );
|
|
local mirror = meta:get_int( 'mirror' );
|
|
|
|
if( not( build_chest.building[ building_name ] )) then
|
|
minetest.chat_send_player( player:get_player_name(), 'Sorry. This building type is not known. Changing it is not possible.');
|
|
return;
|
|
end
|
|
|
|
local replacements_orig = minetest.deserialize( meta:get_string( 'replacements'));
|
|
local replacements = {};
|
|
replacements[ old_material ] = new_material;
|
|
replacements_orig[ old_material ] = new_material;
|
|
meta:set_string( 'replacements', minetest.serialize( replacements_orig ));
|
|
print('SETTING replacements IN upgrade_building');
|
|
random_buildings.build_building( start_pos, building_name, rotate, mirror, platform_materials, replacements_orig, replacements, 0, pos );
|
|
build_chest.update_formspec( pos, 'finished', player );
|
|
end
|
|
|
|
|
|
|
|
-- TODO: check if it is the owner of the chest/village
|
|
build_chest.on_receive_fields = function(pos, formname, fields, player)
|
|
|
|
local meta = minetest.env:get_meta(pos);
|
|
-- general menu handling
|
|
-- back button selected
|
|
if( fields.back ) then
|
|
|
|
local current_path = minetest.deserialize( meta:get_string( 'current_path' ) or 'return {}' );
|
|
|
|
table.remove( current_path ); -- revert latest selection
|
|
meta:set_string( 'current_path', minetest.serialize( current_path ));
|
|
meta:set_string( 'building_name', '');
|
|
meta:set_int( 'replace_row', 0 );
|
|
meta:set_int( 'page_nr', 0 );
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
-- menu entry selected
|
|
elseif( fields.selection ) then
|
|
|
|
local current_path = minetest.deserialize( meta:get_string( 'current_path' ) or 'return {}' );
|
|
table.insert( current_path, fields.selection );
|
|
meta:set_string( 'current_path', minetest.serialize( current_path ));
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
-- if there are more menu items than can be shown on one page: show previous page
|
|
elseif( fields.prev ) then
|
|
local page_nr = meta:get_int( 'page_nr' );
|
|
if( not( page_nr )) then
|
|
page_nr = 0;
|
|
end
|
|
page_nr = math.max( page_nr - 1 );
|
|
meta:set_int( 'page_nr', page_nr );
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
-- if there are more menu items than can be shown on one page: show next page
|
|
elseif( fields.next ) then
|
|
local page_nr = meta:get_int( 'page_nr' );
|
|
if( not( page_nr )) then
|
|
page_nr = 0;
|
|
end
|
|
meta:set_int( 'page_nr', page_nr+1 );
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
-- specific to the build chest
|
|
-- the player has choosen a material from the list; ask for a replacement
|
|
elseif( fields.build_chest_replacements ) then
|
|
local event = minetest.explode_table_event( fields.build_chest_replacements );
|
|
local building_name = meta:get_string('building_name');
|
|
if( event and event.row and event.row > 0
|
|
and building_name
|
|
and build_chest.building[ building_name ] ) then
|
|
|
|
meta:set_int('replace_row', event.row );
|
|
end
|
|
-- build_chest.update_formspec( pos, 'ask_for_replacement', player );
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
-- the player has asked for a particular replacement
|
|
elseif( fields.store_replacement
|
|
and fields.replace_row_with and fields.replace_row_with ~= ""
|
|
and fields.replace_row_material and fields.replace_row_material ~= "") then
|
|
|
|
build_chest.apply_replacement( pos, meta, fields.replace_row_material, fields.replace_row_with );
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
|
|
elseif( fields.proceed_with_scaffolding ) then
|
|
local building_name = meta:get_string('building_name');
|
|
local start_pos = minetest.deserialize( meta:get_string('start_pos'));
|
|
local end_pos = minetest.deserialize( meta:get_string('end_pos'));
|
|
-- TODO: <worldname>/schems/playername_x_y_z_burried_rotation.mts
|
|
local filename = "todo.mts";
|
|
print('CREATING schematic '..tostring( filename )..' from '..minetest.serialize( start_pos )..' to '..minetest.serialize( end_pos ));
|
|
-- store a backup of the original landscape
|
|
minetest.create_schematic( start_pos, end_pos, nil, filename, nil);
|
|
-- place the building
|
|
-- TODO: use scaffolding here (exchange some replacements)
|
|
print('USING ROTATION: '..tostring( meta:get_string('rotate')));
|
|
minetest.place_schematic( start_pos, building_name..'.mts', meta:get_string('rotate'), meta:get_string('replacements'), true );
|
|
meta:set_string('backup', filename );
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
-- restore the original landscape
|
|
elseif( fields.restore_backup ) then
|
|
local start_pos = minetest.deserialize( meta:get_string('start_pos'));
|
|
local end_pos = minetest.deserialize( meta:get_string('end_pos'));
|
|
local backup_file = meta:get_string( 'backup' );
|
|
if( start_pos and end_pos and start_pos.x and end_pos.x and backup_file ) then
|
|
minetest.place_schematic( start_pos, backup_file, "0", {}, true );
|
|
meta:set_string('backup', nil );
|
|
end
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
|
|
|
|
|
|
-- TODO
|
|
-- abort the building - remove scaffolding
|
|
elseif( fields.abort ) then
|
|
|
|
local inv = meta:get_inventory();
|
|
|
|
if( not( inv:is_empty('main' ))) then
|
|
minetest.chat_send_player( player:get_player_name(), 'Please remove the surplus materials first!' );
|
|
return;
|
|
end
|
|
|
|
local start_pos = minetest.deserialize( meta:get_string( 'start_pos' ));
|
|
local building_name = meta:get_string( 'building_name');
|
|
local rotate = meta:get_int( 'rotate' );
|
|
local mirror = meta:get_int( 'mirror' );
|
|
local platform_materials = {};
|
|
local replacements = minetest.deserialize( meta:get_string( 'replacements' ));
|
|
-- action is remove in this case
|
|
random_buildings.build_building( start_pos, building_name, rotate, mirror, platform_materials, replacements, nil, 2, pos );
|
|
|
|
-- reset the needed materials in the building chest
|
|
for i=1,inv:get_size("needed") do
|
|
inv:set_stack("needed", i, nil)
|
|
end
|
|
|
|
meta:set_string( 'current_path', minetest.serialize( {} ));
|
|
meta:set_string( 'building_name', "" );
|
|
meta:set_string( 'material_type', "" );
|
|
build_chest.update_formspec( pos, 'main', player );
|
|
|
|
|
|
|
|
-- chalk the loam to make it white
|
|
elseif( fields.make_white ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:loam', 'default:clay' );
|
|
build_chest.upgrade_building( pos, player, 'default:clay', 'default:clay' );
|
|
|
|
-- turn chalked loam into brick
|
|
elseif( fields.make_brick or fields.make_white) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:loam', 'default:brick' );
|
|
build_chest.upgrade_building( pos, player, 'default:clay', 'default:brick' );
|
|
|
|
-- turn it into stone
|
|
elseif( fields.make_stone ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:loam', 'default:stone' );
|
|
build_chest.upgrade_building( pos, player, 'default:clay', 'default:stone' );
|
|
|
|
-- turn it into cobble
|
|
elseif( fields.make_cobble ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:loam', 'default:cobble' );
|
|
build_chest.upgrade_building( pos, player, 'default:clay', 'default:cobble' );
|
|
|
|
elseif( fields.make_loam ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:loam', 'cottages:loam' );
|
|
build_chest.upgrade_building( pos, player, 'default:clay', 'cottages:loam' );
|
|
|
|
elseif( fields.make_wood ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:loam', 'default:wood' );
|
|
build_chest.upgrade_building( pos, player, 'default:clay', 'default:wood' );
|
|
|
|
elseif( fields.roof_straw ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_straw', 'cottages:roof_straw' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_flat_straw', 'cottages:roof_flat_straw' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_connector_straw', 'cottages:roof_connector_straw' );
|
|
|
|
elseif( fields.roof_tree ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_straw', 'cottages:roof_wood' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_flat_straw', 'cottages:roof_flat_wood' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_connector_straw', 'cottages:roof_connector_wood' );
|
|
|
|
elseif( fields.roof_black ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_straw', 'cottages:roof_black' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_flat_straw', 'cottages:roof_flat_black' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_connector_straw', 'cottages:roof_connector_black' );
|
|
|
|
elseif( fields.roof_red ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_straw', 'cottages:roof_red' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_flat_straw', 'cottages:roof_flat_red' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_connector_straw', 'cottages:roof_connector_red' );
|
|
|
|
elseif( fields.roof_brown ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_straw', 'cottages:roof_brown' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_flat_straw', 'cottages:roof_flat_brown' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:roof_connector_straw', 'cottages:roof_connector_brown' );
|
|
|
|
elseif( fields.make_glass ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:glass_pane', 'cottages:glass_pane' );
|
|
|
|
elseif( fields.make_noglass ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:glass_pane', 'default:fence_wood' );
|
|
|
|
elseif( fields.cobble_cobble ) then
|
|
build_chest.upgrade_building( pos, player, 'default:cobble', 'default:cobble' );
|
|
build_chest.upgrade_building( pos, player, 'stairs:slab_cobble', 'stairs:slab_cobble' );
|
|
|
|
elseif( fields.cobble_brick ) then
|
|
build_chest.upgrade_building( pos, player, 'default:cobble', 'default:stonebrick' );
|
|
build_chest.upgrade_building( pos, player, 'stairs:slab_cobble', 'stairs:slab_stonebrick' );
|
|
|
|
elseif( fields.cobble_stone ) then
|
|
build_chest.upgrade_building( pos, player, 'default:cobble', 'default:stone' );
|
|
build_chest.upgrade_building( pos, player, 'stairs:slab_cobble', 'stairs:slab_stone' );
|
|
|
|
elseif( fields.wood_junglewood ) then
|
|
build_chest.upgrade_building( pos, player, 'default:wood', 'default:junglewood' );
|
|
|
|
elseif( fields.wood_wood ) then
|
|
build_chest.upgrade_building( pos, player, 'default:wood', 'default:wood' );
|
|
|
|
elseif( fields.white_and_jungle ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:clay', 'cottages:clay' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:loam', 'default:junglewood' );
|
|
|
|
elseif( fields.white_and_loam ) then
|
|
build_chest.upgrade_building( pos, player, 'cottages:clay', 'cottages:clay' );
|
|
build_chest.upgrade_building( pos, player, 'cottages:loam', 'cottages:loam' );
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
build_chest.move_trader_in = function( pos )
|
|
|
|
local meta = minetest.env:get_meta( pos );
|
|
local building_name = meta:get_string( 'building_name');
|
|
local rotate = meta:get_int( 'rotate' );
|
|
local start_pos = minetest.deserialize( meta:get_string( 'start_pos' ));
|
|
local menu_path = build_chest.building[ building_name ].menu_path;
|
|
|
|
|
|
local selected_building = build_chest.building[ building_name ];
|
|
local max = {};
|
|
if( rotate == 0 or rotate == 2 ) then
|
|
max = { x = selected_building.max.x, y = selected_building.max.y, z = selected_building.max.z };
|
|
else
|
|
max = { x = selected_building.max.z, y = selected_building.max.y, z = selected_building.max.x };
|
|
end
|
|
|
|
local trader_typ = meta:get_string( 'material_type' );
|
|
if( not( trader_typ )) then
|
|
trader_typ = '';
|
|
end
|
|
|
|
|
|
if( menu_path[2]=='lumberjack' ) then
|
|
-- TODO: realtest-trees?
|
|
trader_typ = trader_typ..'_wood';
|
|
|
|
elseif( menu_path[2]=='clay' ) then
|
|
trader_typ = 'clay';
|
|
|
|
elseif( menu_path[2]=='small_farm' ) then
|
|
trader_typ = trader_typ..'_farmer';
|
|
|
|
else
|
|
trader_typ = '';
|
|
end
|
|
|
|
-- actually spawn the trader
|
|
if( trader_typ ~= '' ) then
|
|
random_buildings.spawn_trader_at_building( start_pos, max, trader_typ );
|
|
end
|
|
end
|
|
|
|
|
|
|
|
build_chest.on_metadata_inventory_put = function( pos, listname, index, stack, player )
|
|
|
|
local meta = minetest.env:get_meta( pos );
|
|
local inv = meta:get_inventory();
|
|
local input = stack:get_name();
|
|
local stage = meta:get_int( 'building_stage' );
|
|
|
|
-- this item is not needed
|
|
if( not( stack ) or not(input) or not( inv:contains_item( 'needed', input..' 1' ))) then
|
|
return;
|
|
end
|
|
|
|
-- find out how many of that item we nee
|
|
local anz_needed = 0;
|
|
local gesucht = "";
|
|
for i=1,inv:get_size("needed") do
|
|
gesucht = inv:get_stack( 'needed', i );
|
|
if( gesucht:get_name() == input ) then
|
|
anz_needed = gesucht:get_count();
|
|
end
|
|
end
|
|
|
|
-- not enough input yet
|
|
if( anz_needed < 1 or not( inv:contains_item( 'main', input..' '..anz_needed ))) then
|
|
return;
|
|
end
|
|
inv:remove_item( 'main', input..' '..anz_needed );
|
|
inv:remove_item( 'needed', input..' '..anz_needed );
|
|
|
|
|
|
local start_pos = minetest.deserialize( meta:get_string( 'start_pos' ));
|
|
local building_name = meta:get_string( 'building_name');
|
|
local rotate = meta:get_int( 'rotate' );
|
|
local mirror = meta:get_int( 'mirror' );
|
|
local replacements_orig = minetest.deserialize( meta:get_string( 'replacements' ));
|
|
local platform_materials = {};
|
|
local replacements = {};
|
|
|
|
local menu_path = build_chest.building[ building_name ].menu_path;
|
|
|
|
|
|
-- all parts for the building have been supplied
|
|
if( inv:is_empty( 'needed')) then
|
|
|
|
if( stage==nil or stage < 6 ) then
|
|
build_chest.update_needed_list( pos, stage+1 ); -- request the material for the very first building step
|
|
else
|
|
|
|
-- there are leftover parts that need to be removed
|
|
if( not( inv:is_empty( 'main' ))) then
|
|
build_chest.update_formspec( pos, 'please_remove', player );
|
|
else
|
|
-- show the finished formspec
|
|
build_chest.update_formspec( pos, 'finished', player );
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- straw is good for a lot of things! (mostly roof and beds)
|
|
if( input == 'cottages:straw_bale' ) then
|
|
|
|
replacements[ 'cottages:roof' ] = 'cottages:roof_straw';
|
|
replacements[ 'cottages:roof_connector' ] = 'cottages:roof_connector_straw';
|
|
replacements[ 'cottages:roof_flat' ] = 'cottages:roof_flat_straw';
|
|
replacements[ 'cottages:roof_straw' ] = 'cottages:roof_straw';
|
|
replacements[ 'cottages:roof_connector_straw'] = 'cottages:roof_connector_straw';
|
|
replacements[ 'cottages:roof_flat_straw' ] = 'cottages:roof_flat_straw';
|
|
|
|
replacements[ 'cottages:bed_head' ] = 'cottages:straw_mat';
|
|
replacements[ 'cottages:bed_foot' ] = 'cottages:straw_mat';
|
|
replacements[ 'cottages:sleeping_mat' ] = 'cottages:straw_mat';
|
|
replacements[ 'cottages:straw_mat' ] = 'cottages:straw_mat';
|
|
|
|
elseif( input == 'cottages:sleeping_mat' ) then
|
|
|
|
replacements[ 'cottages:bed_head' ] = 'cottages:sleeping_mat';
|
|
replacements[ 'cottages:bed_foot' ] = 'cottages:sleeping_mat';
|
|
replacements[ 'cottages:sleeping_mat' ] = 'cottages:sleeping_mat';
|
|
|
|
elseif( input == 'cottages:bed_head' ) then
|
|
replacements[ 'cottages:bed_head' ] = 'cottages:bed_head';
|
|
|
|
elseif( input == 'cottages:bed_foot' ) then
|
|
replacements[ 'cottages:bed_foot' ] = 'cottages:bed_foot';
|
|
|
|
-- wooden slabs and stairs are included in the wood
|
|
elseif( input == 'default:wood' ) then
|
|
|
|
replacements[ 'default:wood' ] = 'default:wood';
|
|
replacements[ 'stairs:slab_wood' ] = 'stairs:slab_wood';
|
|
replacements[ 'stairs:stair_wood' ] = 'stairs:stair_wood';
|
|
replacements[ 'stairs:slab_woodupside_down' ] = 'stairs:slab_woodupside_down';
|
|
|
|
-- same applies to cobble - no need to create seperate slabs
|
|
elseif( input == 'default:cobble' ) then
|
|
|
|
replacements[ 'default:cobble' ] = 'default:cobble';
|
|
replacements[ 'stairs:slab_cobble' ] = 'stairs:slab_cobble';
|
|
replacements[ 'stairs:stair_cobble' ] = 'stairs:stair_cobble';
|
|
replacements[ 'stairs:slab_cobbleupside_down' ] = 'stairs:slab_cobbleupside_down';
|
|
|
|
-- the first windows are built using fences
|
|
elseif( input == 'default:fence_wood' ) then
|
|
|
|
replacements[ 'default:fence_wood' ] = 'default:fence_wood';
|
|
replacements[ 'cottages:glass_pane' ] = 'default:fence_wood';
|
|
|
|
-- there are four nodes representing doors - replace them all
|
|
elseif( input == 'doors:door_wood' ) then
|
|
|
|
replacements[ 'doors:door_wood_t_1' ] = 'doors:door_wood_t_1';
|
|
replacements[ 'doors:door_wood_t_2' ] = 'doors:door_wood_t_2';
|
|
replacements[ 'doors:door_wood_b_1' ] = 'doors:door_wood_b_1';
|
|
replacements[ 'doors:door_wood_b_2' ] = 'doors:door_wood_b_2';
|
|
|
|
-- work on the land
|
|
elseif( input == 'farming:hoe_steel' ) then
|
|
|
|
local possible_types = {'cotton','carrot', 'orange', 'potatoe', 'rhubarb', 'strawberry', 'tomato' };
|
|
local typ = possible_types[ math.random(1,#possible_types) ];
|
|
|
|
meta:set_string( 'material_typ', typ );
|
|
|
|
replacements[ 'farming:soil' ] = 'farming:soil_wet';
|
|
replacements[ 'farming:soil_wet' ] = 'farming:soil_wet'; -- makes it easier for protection
|
|
|
|
replacements[ 'farming:cotton' ] = 'farming:'..typ..'_1'; -- seeds need to grow manually
|
|
replacements[ 'farming:cotton_1' ] = 'farming:'..typ..'_1';
|
|
replacements[ 'farming:cotton_2' ] = 'farming:'..typ..'_1';
|
|
replacements[ 'farming:cotton_3' ] = 'farming:'..typ..'_1';
|
|
|
|
|
|
--
|
|
-- lumberjacks know how to use an axe
|
|
--
|
|
elseif( input == 'default:axe_mese'
|
|
and menu_path[2]=='lumberjack' ) then
|
|
tree_typ = meta:get_string( 'material_type' );
|
|
|
|
if( tree_typ == 'normal' ) then
|
|
tree_typ = 'common';
|
|
elseif( tree_typ == 'apple tree' ) then
|
|
tree_typ = 'apple_tree';
|
|
elseif( tree_typ == 'rubber tree' ) then
|
|
tree_typ = 'rubber_tree';
|
|
elseif( tree_typ == 'jungletree' ) then
|
|
tree_typ = 'jungle_tree';
|
|
end
|
|
|
|
-- realtest trees
|
|
if( tree_typ ~= 'common' and (tree_typ == 'ash (small)' or tree_typ == 'aspen (small)' or tree_typ == 'birch (small)'
|
|
or tree_typ == 'maple (small)' or tree_typ == 'chestnut (small)' or tree_typ == 'pine (small)'
|
|
or tree_typ == 'spruce (small)' )) then
|
|
|
|
-- TODO: pretty chaotic...
|
|
if( tree_typ == 'ash (small)' ) then tree_typ = 'ash';
|
|
elseif( tree_typ == 'aspen (small)' ) then tree_typ = 'aspen';
|
|
elseif( tree_typ == 'birch (small)' ) then tree_typ = 'birch';
|
|
elseif( tree_typ == 'maple (small)' ) then tree_typ = 'maple';
|
|
elseif( tree_typ == 'chestnut (small)') then tree_typ = 'chestnut';
|
|
elseif( tree_typ == 'pine (small)' ) then tree_typ = 'pine';
|
|
elseif( tree_typ == 'spruce (small)' ) then tree_typ = 'spruce';
|
|
end
|
|
|
|
replacements[ 'moretrees:TYP_planks' ] = 'trees:'..tree_typ..'_planks';
|
|
replacements[ 'moretrees:TYP_trunk' ] = 'trees:'..tree_typ..'_trunk';
|
|
replacements[ 'moretrees:TYP_trunk_sideways' ] = 'trees:'..tree_typ..'_trunk'; -- those are now normal trunks rotated
|
|
replacements[ 'moretrees:slab_TYP_planks' ] = 'trees:'..tree_typ..'_planks_slab'; -- those are now normal trunks rotated
|
|
|
|
elseif( tree_typ ~= 'common' and minetest.get_modpath("moretrees") ~= nil ) then
|
|
replacements[ 'moretrees:TYP_planks' ] = 'moretrees:'..tree_typ..'_planks';
|
|
replacements[ 'moretrees:TYP_trunk' ] = 'moretrees:'..tree_typ..'_trunk';
|
|
replacements[ 'moretrees:TYP_trunk_sideways' ] = 'moretrees:'..tree_typ..'_trunk'; -- those are now normal trunks rotated
|
|
|
|
else
|
|
replacements[ 'moretrees:TYP_planks' ] = 'default:wood';
|
|
replacements[ 'moretrees:TYP_trunk' ] = 'default:tree';
|
|
replacements[ 'moretrees:TYP_trunk_sideways' ] = 'default:tree';
|
|
end
|
|
|
|
-- TODO: replacement of wooden slabs for now disabled - because the normal wood forms a nicer contrast
|
|
if( false and minetest.registered_nodes[ 'moretrees:slab_'..tree_typ..'_planks' ] ) then
|
|
replacements[ 'moretrees:slab_TYP_planks' ] = 'moretrees:slab_'..tree_typ..'_planks'; -- those are now normal trunks rotated
|
|
else
|
|
replacements[ 'moretrees:slab_TYP_planks' ] = 'stairs:slab_wood'; -- those are now normal trunks rotated
|
|
end
|
|
|
|
-- lumberjacks do their own roof
|
|
replacements[ 'cottages:roof_wood' ] = 'cottages:roof_wood';
|
|
replacements[ 'cottages:roof_connector_wood' ] = 'cottages:roof_connector_wood';
|
|
replacements[ 'cottages:roof_flat_wood' ] = 'cottages:roof_flat_wood';
|
|
|
|
--
|
|
-- this is intresting for clay traders - they know how to use a shovel
|
|
--
|
|
elseif( input == 'default:shovel_mese'
|
|
and menu_path[2]=='clay' ) then
|
|
|
|
replacements[ 'default:clay' ] = 'default:clay';
|
|
replacements[ 'default:sand' ] = 'default:sand';
|
|
replacements[ 'default:desert_sand' ] = 'default:desert_sand';
|
|
replacements[ 'default:sandstone' ] = 'default:sandstone';
|
|
replacements[ 'default:sandstonebrick' ] = 'default:sandstonebrick';
|
|
|
|
replacements[ 'stairs:slab_sandstone' ] = 'stairs:slab_sandstone';
|
|
replacements[ 'stairs:slab_sandstonebrick' ] = 'stairs:slab_sandstonebrick';
|
|
|
|
|
|
--
|
|
-- clay traders are also quite capable of using a furnace
|
|
--
|
|
elseif( input == 'default:furnace'
|
|
and menu_path[2]=='clay' ) then
|
|
replacements[ 'default:brick' ] = 'default:brick';
|
|
replacements[ 'default:glass' ] = 'default:glass';
|
|
|
|
replacements[ 'stairs:slab_brick' ] = 'stairs:slab_brick';
|
|
replacements[ 'stairs:slab_glass' ] = 'stairs:slab_glass';
|
|
|
|
replacements[ 'default:furnace' ] = 'default:furnace';
|
|
|
|
|
|
-- TODO: change the house blueprints
|
|
replacements[ 'default:stone' ] = 'default:stone';
|
|
replacements[ 'stairs:slab_stone' ] = 'cottages:roof_flat_red';
|
|
replacements[ 'stairs:stair_stone' ] = 'cottages:roof_red';
|
|
|
|
|
|
elseif( input == 'cottages:half_door'
|
|
or input == 'cottages:half_door_inverted' ) then
|
|
|
|
replacements[ 'cottages:half_door_inverted' ] = 'cottages:half_door_inverted';
|
|
replacements[ 'cottages:half_door' ] = 'cottages:half_door';
|
|
|
|
|
|
elseif( input == 'cottages:gate_open'
|
|
or input == 'cottages:gate_closed' ) then
|
|
|
|
replacements[ 'cottages:gate_open' ] = 'cottages:gate_open';
|
|
replacements[ 'cottages:gate_closed' ] = 'cottages:gate_closed';
|
|
|
|
elseif( input == 'cottages:window_shutter_open'
|
|
or input == 'cottages:window_shutter_closed' ) then
|
|
|
|
replacements[ 'cottages:window_shutter_open' ] = 'cottages:window_shutter_open';
|
|
replacements[ 'cottages:window_shutter_closed'] = 'cottages:window_shutter_closed';
|
|
|
|
-- we got water!
|
|
elseif( input == 'bucket:bucket_water' ) then
|
|
|
|
replacements[ 'default:water_source' ] = 'default:water_source';
|
|
replacements[ 'farming:soil' ] = 'farming:soil_wet'; -- so that the protection can work
|
|
|
|
elseif( input == 'cottages:barrel' ) then
|
|
|
|
replacements[ 'cottages:barrel' ] = 'cottages:barrel';
|
|
replacements[ 'cottages:barrel_open' ] = 'cottages:barrel_open';
|
|
replacements[ 'cottages:barrel_lying' ] = 'cottages:barrel_lying';
|
|
replacements[ 'cottages:barrel_lying_open' ] = 'cottages:barrel_lying_open';
|
|
|
|
-- lets hope the house is ready for the lava...
|
|
elseif( input == 'bucket:bucket_lava' ) then
|
|
|
|
replacements[ 'default:lava_source' ] = 'default:lava_source';
|
|
|
|
-- this is special for the farm_*.we buildings
|
|
elseif( input == 'cottages:loam' ) then
|
|
|
|
replacements[ 'default:sandstone' ] = 'cottages:loam';
|
|
replacements[ 'default:clay' ] = 'cottages:loam';
|
|
replacements[ 'cottages:straw_ground' ] = 'cottages:loam';
|
|
replacements[ 'cottages:loam' ] = 'cottages:loam';
|
|
|
|
-- ...and normal chests replace the privat/work/storage chests that are special for npc
|
|
elseif( input == 'default:chest' ) then
|
|
|
|
replacements[ 'cottages:chest_private'] = 'cottages:chest_private';
|
|
replacements[ 'cottages:chest_work' ] = 'cottages:chest_work' ;
|
|
replacements[ 'cottages:chest_storage'] = 'cottages:chest_storage';
|
|
replacements[ 'default:chest'] = 'default:chest';
|
|
|
|
elseif( input == 'cottages:roof' ) then
|
|
replacements[ 'cottages:roof' ] = 'cottages:roof_straw';
|
|
elseif( input == 'cottages:roof_flat' ) then
|
|
replacements[ 'cottages:roof_flat' ] = 'cottages:roof_flat_straw';
|
|
elseif( input == 'cottages:roof_connector' ) then
|
|
replacements[ 'cottages:roof_connector' ] = 'cottages:roof_connector_straw';
|
|
|
|
-- we got normal input that can be used directly
|
|
elseif( replacements_orig[ input ]==build_chest.SUPPORT ) then
|
|
replacements[ input ] = input;
|
|
end
|
|
|
|
for k,v in pairs( replacements_orig ) do
|
|
if( replacements[ k ] ) then
|
|
replacements_orig[ k ] = replacements[ k ];
|
|
end
|
|
end
|
|
meta:set_string( 'replacements', minetest.serialize( replacements_orig ));
|
|
random_buildings.build_building( start_pos, building_name, rotate, mirror, platform_materials, replacements_orig, replacements, 0, pos );
|
|
end
|
|
|
|
|
|
minetest.register_node("mg_villages:build", { --TODO
|
|
description = "Building-Spawner",
|
|
tiles = {"default_chest_side.png", "default_chest_top.png", "default_chest_side.png",
|
|
"default_chest_side.png", "default_chest_side.png", "default_chest_front.png"},
|
|
-- drawtype = 'signlike',
|
|
-- paramtype = "light",
|
|
-- paramtype2 = "wallmounted",
|
|
-- sunlight_propagates = true,
|
|
-- walkable = false,
|
|
-- selection_box = {
|
|
-- type = "wallmounted",
|
|
-- },
|
|
|
|
paramtype2 = "facedir",
|
|
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
|
|
legacy_facedir_simple = true,
|
|
after_place_node = function(pos, placer, itemstack)
|
|
|
|
-- TODO: check if placement is allowed
|
|
|
|
local meta = minetest.env:get_meta( pos );
|
|
meta:set_string( 'current_path', minetest.serialize( {} ));
|
|
meta:set_string( 'village', 'BEISPIELSTADT' ); --TODO
|
|
meta:set_string( 'village_pos', minetest.serialize( {x=1,y=2,z=3} )); -- TODO
|
|
meta:set_string( 'owner', placer:get_player_name());
|
|
|
|
build_chest.update_formspec( pos, 'main', placer );
|
|
end,
|
|
on_receive_fields = function( pos, formname, fields, player )
|
|
return build_chest.on_receive_fields(pos, formname, fields, player);
|
|
end,
|
|
-- taken from towntest
|
|
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
|
if from_list=="needed" or to_list=="needed" then return 0 end
|
|
return count
|
|
end,
|
|
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
if listname=="needed" then return 0 end
|
|
return stack:get_count()
|
|
end,
|
|
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
|
if listname=="needed" then return 0 end
|
|
-- if listname=="lumberjack" then return 0 end
|
|
return stack:get_count()
|
|
end,
|
|
|
|
can_dig = function(pos,player)
|
|
local meta = minetest.env:get_meta( pos );
|
|
local inv = meta:get_inventory();
|
|
local owner_name = meta:get_string( 'owner' );
|
|
local building_name = meta:get_string( 'building_name' );
|
|
local name = player:get_player_name();
|
|
|
|
if( not( meta ) or not( owner_name )) then
|
|
return true;
|
|
end
|
|
if( owner_name ~= name ) then
|
|
minetest.chat_send_player(name, "This building chest belongs to "..tostring( owner_name )..". You can't take it.");
|
|
return false;
|
|
end
|
|
if( building_name ~= nil and building_name ~= "" ) then
|
|
minetest.chat_send_player(name, "This building chest has been assigned to a building project. You can't take it away now.");
|
|
return false;
|
|
end
|
|
return true;
|
|
end,
|
|
|
|
-- have all materials been supplied and the remaining parts removed?
|
|
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
|
local meta = minetest.env:get_meta( pos );
|
|
local inv = meta:get_inventory();
|
|
local stage = meta:get_int( 'building_stage' );
|
|
|
|
if( inv:is_empty( 'needed' ) and inv:is_empty( 'main' )) then
|
|
if( stage==nil or stage < 6 ) then
|
|
build_chest.update_needed_list( pos, stage+1 ); -- request the material for the very first building step
|
|
else
|
|
build_chest.update_formspec( pos, 'finished', player );
|
|
end
|
|
end
|
|
end,
|
|
|
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
return build_chest.on_metadata_inventory_put( pos, listname, index, stack, player );
|
|
end,
|
|
|
|
})
|
|
|
|
|