village types can now be added later on

master
Sokomine 2014-12-13 05:59:09 +01:00
parent 7bcd2bcf4a
commit fc1ec121d8
2 changed files with 177 additions and 123 deletions

View File

@ -15,7 +15,7 @@
-- of villages, the village name will consist of name_prefix..village_name..name_postfix
mg_villages.village_type_data = {
mg_villages.village_type_data_list = {
nore = { min = 20, max = 40, space_between_buildings=1, mods={}, texture = 'default_stone_brick.png'},
taoki = { min = 30, max = 70, space_between_buildings=1, mods={}, texture = 'default_brick.png' },
medieval = { min = 25, max = 60, space_between_buildings=2, mods={'cottages'}, texture = 'cottages_darkage_straw.png'}, -- they often have straw roofs
@ -41,29 +41,37 @@ mg_villages.village_type_data = {
}
-- list of village types supported by the mods installed
-- (some villages require special mods as building material for their houses)
mg_villages.village_types = {};
for k,v in pairs( mg_villages.village_type_data ) do
-- some villages require special mods as building material for their houses;
-- figure out which village types can be used
mg_villages.add_village_type = function( type_name, v )
local found = true;
if( not( v.mods )) then
v.mods = {};
end
for _,m in ipairs( v.mods ) do
if( not( minetest.get_modpath( m ))) then
found = false;
-- this village type will not be used because not all required mods are installed
return false;
end
end
if( found ) then
if( not( v.only_single )) then
table.insert( mg_villages.village_types, k );
end
-- this village type is supported by the mods installed and may be used
v.supported = 1;
if( not( v.only_single ) and (not(v.min) or not(v.max))) then
print('[mg_villages] Error: Village type '..tostring( type_name )..' lacks size information.');
return false;
end
-- this village type is supported by the mods installed and may be used
v.supported = 1;
mg_villages.village_type_data[ type_name ] = v;
return true;
end
print('[mg_villages] Will create villages of the following types: '..minetest.serialize( mg_villages.village_types ));
-- build a list of all useable village types
mg_villages.village_type_data = {};
for k,v in pairs( mg_villages.village_type_data_list ) do
mg_villages.add_village_type( k, v );
end
@ -90,7 +98,7 @@ mg_villages.medieval_subtype = false;
-- inh=2 maximum amount of inhabitants the building may hold (usually amount of beds present)
-- if set to i.e. -1, this indicates that a mob is WORKING, but not LIVING here
mg_villages.BUILDINGS = {
mg_villages.ALL_BUILDINGS = {
-- the houses the mod came with
{yoff= 0, scm="house", orients={2}, weight={nore=1, single=2 }, inh=4},
@ -331,120 +339,154 @@ mg_villages.BUILDINGS = {
-- read the data files and fill in information like size and nodes that need on_construct to be called after placing
mg_villages.buildings_init = function()
-- read the data files and fill in information like size and nodes that need on_construct to be called after placing;
-- skip buildings that cannot be used due to missing mods
mg_villages.add_building = function( building_data )
local mts_path = mg_villages.modpath.."/schems/";
-- determine the size of the given houses
for i,v in ipairs( mg_villages.BUILDINGS ) do
local is_used = false;
for typ,weight in pairs( v.weight ) do
if( typ and weight and weight>0 and mg_villages.village_type_data[ typ ] and mg_villages.village_type_data[ typ ].supported ) then
is_used = true;
end
-- a building will only be used if it is used by at least one supported village type (=mods required for that village type are installed)
local is_used = false;
for typ,weight in pairs( building_data.weight ) do
if( typ and weight and weight>0 and mg_villages.village_type_data[ typ ] and mg_villages.village_type_data[ typ ].supported ) then
is_used = true;
end
local res = nil;
if( is_used ) then
-- read the size of the building
res = handle_schematics.analyze_mts_file( mts_path..mg_villages.BUILDINGS[ i ].scm );
-- alternatively, read the mts file
if( not( res )) then
res = mg_villages.import_scm( mg_villages.BUILDINGS[ i ].scm );
end
-- create lists for all village types containing the buildings which may be used for that village
for typ, data in pairs( mg_villages.village_type_data ) do
local total_weight = 0;
if( not( data.building_list ) or not( data.max_weight_list )) then
data.building_list = {};
data.max_weight_list = {};
elseif( #data.max_weight_list > 0 ) then
-- get the last entry - that one will determine the current total_weight
total_weight = data.max_weight_list[ #data.max_weight_list ];
end
if( v.weight and v.weight[ typ ] and v.weight[ typ ] > 0 ) then
local index = #data.building_list+1;
data.building_list[ index ] = i;
data.max_weight_list[ index ] = total_weight + v.weight[ typ ];
end
end
end
if( not( is_used )) then
-- do nothing; skip this file
print('SKIPPING '..tostring( mg_villages.BUILDINGS[ i ].scm )..' due to village type not supported.');
-- building cannot be used
v.not_available = 1;
-- provided the file could be analyzed successfully
elseif( res and res.size and res.size.x ) then
-- the file has to be placed with minetest.place_schematic(...)
mg_villages.BUILDINGS[ i ].is_mts = 1;
mg_villages.BUILDINGS[ i ].sizex = res.size.x;
mg_villages.BUILDINGS[ i ].sizez = res.size.z;
mg_villages.BUILDINGS[ i ].ysize = res.size.y;
-- some buildings may be rotated
if( res.rotated == 90
or res.rotated == 270 ) then
mg_villages.BUILDINGS[ i ].sizex = res.size.z;
mg_villages.BUILDINGS[ i ].sizez = res.size.x;
end
if( not( mg_villages.BUILDINGS[ i ].yoff ) or mg_villages.BUILDINGS[ i ].yoff == 0 ) then
mg_villages.BUILDINGS[ i ].yoff = res.burried;
end
-- we do need at least the list of nodenames which will need on_constr later on
mg_villages.BUILDINGS[ i ].rotated = res.rotated;
mg_villages.BUILDINGS[ i ].nodenames = res.nodenames;
mg_villages.BUILDINGS[ i ].on_constr = res.on_constr;
mg_villages.BUILDINGS[ i ].after_place_node = res.after_place_node;
if( res.scm_data_cache ) then
mg_villages.BUILDINGS[ i ].scm_data_cache = res.scm_data_cache;
mg_villages.BUILDINGS[ i ].is_mts = 0;
end
-- determine size of worldedit schematics
elseif( res and #res and #res>0 and #res[1] and #res[1][1]) then
-- scm has the following structure: scm[y][x][z]
mg_villages.BUILDINGS[ i ].ysize = #res;
mg_villages.BUILDINGS[ i ].sizex = #res[1];
mg_villages.BUILDINGS[ i ].sizez = #res[1][1];
mg_villages.BUILDINGS[ i ].is_mts = 0;
-- cache the data for later placement
mg_villages.BUILDINGS[ i ].scm_data_cache = res;
-- deep copy the schematics data here so that the file does not have to be read again
-- caching cannot be done here as not all nodes from other mods have been registered yet!
--buildings[ i ].scm_data_cache = minetest.serialize( res );
-- missing data regarding building size - do not use this building for anything
elseif( not( mg_villages.BUILDINGS[ i ].sizex ) or not( mg_villages.BUILDINGS[ i ].sizez )
or mg_villages.BUILDINGS[ i ].sizex == 0 or mg_villages.BUILDINGS[ i ].sizez==0) then
-- no village will use it
print('[mg_villages] INFO: No schematic found for building \''..tostring( mg_villages.BUILDINGS[ i ].scm )..'\'. Will not use that building.');
mg_villages.BUILDINGS[ i ].weight = {};
else
-- the file has to be handled by worldedit; it is no .mts file
mg_villages.BUILDINGS[ i ].is_mts = 0;
end
-- print it for debugging usage
--print( v.scm .. ': '..tostring(buildings[i].sizex)..' x '..tostring(buildings[i].sizez)..' x '..tostring(buildings[i].ysize)..' h');
end
if( not( is_used )) then
-- do nothing; skip this file
print('SKIPPING '..tostring( building_data.scm )..' due to village type not supported.');
-- building cannot be used
building_data.not_available = 1;
return false;
end
-- determine the size of the building
local res = nil;
-- read the size of the building
res = handle_schematics.analyze_mts_file( building_data.mts_path .. building_data.scm );
-- alternatively, read the mts file
if( not( res )) then
res = mg_villages.import_scm( building_data.mts_path .. building_data.scm );
end
if( not( res )) then
print('SKIPPING '..tostring( building_data.scm )..' due to import failure.');
building_data.not_available = 1;
return false;
-- provided the file could be analyzed successfully
elseif( res and res.size and res.size.x ) then
-- the file has to be placed with minetest.place_schematic(...)
building_data.is_mts = 1;
building_data.sizex = res.size.x;
building_data.sizez = res.size.z;
building_data.ysize = res.size.y;
-- some buildings may be rotated
if( res.rotated == 90
or res.rotated == 270 ) then
building_data.sizex = res.size.z;
building_data.sizez = res.size.x;
end
if( not( building_data.yoff ) or building_data.yoff == 0 ) then
building_data.yoff = res.burried;
end
-- we do need at least the list of nodenames which will need on_constr later on
building_data.rotated = res.rotated;
building_data.nodenames = res.nodenames;
building_data.on_constr = res.on_constr;
building_data.after_place_node = res.after_place_node;
if( res.scm_data_cache ) then
building_data.scm_data_cache = res.scm_data_cache;
building_data.is_mts = 0;
end
-- determine size of worldedit schematics
elseif( res and #res and #res>0 and #res[1] and #res[1][1]) then
-- scm has the following structure: scm[y][x][z]
building_data.ysize = #res;
building_data.sizex = #res[1];
building_data.sizez = #res[1][1];
building_data.is_mts = 0;
-- cache the data for later placement
building_data.scm_data_cache = res;
-- deep copy the schematics data here so that the file does not have to be read again
-- caching cannot be done here as not all nodes from other mods have been registered yet!
--buildings[ i ].scm_data_cache = minetest.serialize( res );
-- missing data regarding building size - do not use this building for anything
elseif( not( building_data.sizex ) or not( building_data.sizez )
or building_data.sizex == 0 or building_data.sizez==0) then
-- no village will use it
print('[mg_villages] INFO: No schematic found for building \''..tostring( building_data.scm )..'\'. Will not use that building.');
building_data.weight = {};
building_data.not_available = 1;
return false;
else
-- the file has to be handled by worldedit; it is no .mts file
building_data.is_mts = 0;
end
if( not( building_data.weight ) or type( building_data.weight ) ~= 'table' ) then
print('SKIPPING '..tostring( building_data.scm )..' due to missing weight information.');
building_data.not_available = 1;
return false;
end
-- TODO: handle duplicates; make sure buildings always get the same number
-- determine the internal number for the building; this number is used as a key and can be found in the mg_all_villages.data file
if( not( mg_villages.BUILDINGS )) then
mg_villages.BUILDINGS = {};
end
local internal_number = #mg_villages.BUILDINGS + 1;
-- actually store the building data
mg_villages.BUILDINGS[ internal_number ] = minetest.deserialize( minetest.serialize( building_data ));
-- create lists for all village types containing the buildings which may be used for that village
for typ, data in pairs( mg_villages.village_type_data ) do
local total_weight = 0;
if( not( data.building_list ) or not( data.max_weight_list )) then
data.building_list = {};
data.max_weight_list = {};
elseif( #data.max_weight_list > 0 ) then
-- get the last entry - that one will determine the current total_weight
total_weight = data.max_weight_list[ #data.max_weight_list ];
end
if( building_data.weight[ typ ] and building_data.weight[ typ ] > 0 ) then
local index = #data.building_list+1;
data.building_list[ index ] = internal_number;
data.max_weight_list[ index ] = total_weight + building_data.weight[ typ ];
end
end
-- print it for debugging usage
--print( v.scm .. ': '..tostring(buildings[i].sizex)..' x '..tostring(buildings[i].sizez)..' x '..tostring(buildings[i].ysize)..' h');
return true;
end
-- import all the buildings
mg_villages.BUILDINGS = {};
local mts_path = mg_villages.modpath.."/schems/";
-- determine the size of the given houses and other necessary values
for i,v in ipairs( mg_villages.ALL_BUILDINGS ) do
v.mts_path = mts_path;
mg_villages.add_building( v, i );
end
-- call the initialization function above
mg_villages.buildings_init();
--local gravel = minetest.get_content_id("default:gravel")
@ -491,6 +533,18 @@ mg_villages.BUILDINGS["wall"] = {yoff = 1, ysize = 6, scm = wall}
-- create a list of all used village types
mg_villages.village_types = {};
for k,v in pairs( mg_villages.village_type_data ) do
if( not( v.only_single ) and v.supported and v.building_list ) then
table.insert( mg_villages.village_types, k );
end
end
print('[mg_villages] Will create villages of the following types: '..minetest.serialize( mg_villages.village_types ));
mg_villages.village_types[ #mg_villages.village_types+1 ] = 'single';
mg_villages.village_types[ #mg_villages.village_types+1 ] = 'fields';
mg_villages.village_types[ #mg_villages.village_types+1 ] = 'tower';

2
we.lua
View File

@ -36,7 +36,7 @@ mg_villages.import_scm = function(scm)
-- check if it is a worldedit file
-- (no idea why reading that is done in such a complicated way; a simple deserialize and iteration over all nodes ought to do as well)
local f, err = io.open( mg_villages.modpath.."/schems/"..scm..".we", "r")
local f, err = io.open( scm..".we", "r")
if not f then
error("Could not open schematic '" .. scm .. ".we': " .. err)
return {};