ESM UPDATE 2.0
major overhaul
@ -1,10 +0,0 @@
|
|||||||
[mod] Hazmat Suit [hazmat_suit]
|
|
||||||
===================================
|
|
||||||
|
|
||||||
Adds hazmat suit to 3d_armor. It protects rather well from fire (if enabled in configuration) and radiation, and it has built-in oxygen supply.
|
|
||||||
Requires technic mod.
|
|
||||||
|
|
||||||
Depends: 3d_armor, technic
|
|
||||||
|
|
||||||
Source code by numZero
|
|
||||||
Textures by HybridDog and numZero
|
|
@ -1,2 +0,0 @@
|
|||||||
3d_armor
|
|
||||||
es
|
|
@ -1 +0,0 @@
|
|||||||
Adds hazmat suit (protects from water, fire and radiation) to 3d_armor.
|
|
@ -1,126 +0,0 @@
|
|||||||
local part_count = 4
|
|
||||||
|
|
||||||
local level = 35
|
|
||||||
local heal = 20
|
|
||||||
local use = 1000
|
|
||||||
local fire = 4
|
|
||||||
local water = 1
|
|
||||||
local radiation = 50
|
|
||||||
|
|
||||||
if minetest.get_modpath("shields") then
|
|
||||||
level = level / 0.9
|
|
||||||
end
|
|
||||||
|
|
||||||
if part_count == #armor.elements then
|
|
||||||
level = level / 1.1
|
|
||||||
end
|
|
||||||
|
|
||||||
level = math.floor(level / part_count)
|
|
||||||
heal = math.floor(heal / part_count)
|
|
||||||
fire = math.floor(fire / part_count)
|
|
||||||
radiation = math.floor(radiation / part_count)
|
|
||||||
|
|
||||||
minetest.register_craftitem("hazmat_suit:helmet_hazmat", {
|
|
||||||
description = "Hazmat Helmet",
|
|
||||||
inventory_image = "hazmat_suit_inv_helmet_hazmat.png",
|
|
||||||
stack_max = 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craftitem("hazmat_suit:chestplate_hazmat", {
|
|
||||||
description = "Hazmat Chestplate",
|
|
||||||
inventory_image = "hazmat_suit_inv_chestplate_hazmat.png",
|
|
||||||
stack_max = 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craftitem("hazmat_suit:sleeve_hazmat", {
|
|
||||||
description = "Hazmat Sleeve",
|
|
||||||
inventory_image = "hazmat_suit_inv_sleeve_hazmat.png",
|
|
||||||
stack_max = 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craftitem("hazmat_suit:leggings_hazmat", {
|
|
||||||
description = "Hazmat Leggins",
|
|
||||||
inventory_image = "hazmat_suit_inv_leggings_hazmat.png",
|
|
||||||
stack_max = 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craftitem("hazmat_suit:boots_hazmat", {
|
|
||||||
description = "Hazmat Boots",
|
|
||||||
inventory_image = "hazmat_suit_inv_boots_hazmat.png",
|
|
||||||
stack_max = 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_tool("hazmat_suit:suit_hazmat", {
|
|
||||||
description = "Hazmat Suit",
|
|
||||||
inventory_image = "hazmat_suit_inv_suit_hazmat.png",
|
|
||||||
groups = {
|
|
||||||
armor_head = level,
|
|
||||||
armor_torso = level,
|
|
||||||
armor_legs = level,
|
|
||||||
armor_feet = level,
|
|
||||||
armor_heal = heal,
|
|
||||||
armor_use = use,
|
|
||||||
armor_fire = fire,
|
|
||||||
armor_water = water,
|
|
||||||
armor_radiation = radiation,
|
|
||||||
},
|
|
||||||
wear = 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "hazmat_suit:helmet_hazmat",
|
|
||||||
recipe = {
|
|
||||||
{"", "es:infinium_ingot", ""},
|
|
||||||
{"es:infinium_ingot", "default:glass", "es:infinium_ingot"},
|
|
||||||
{"es:rubber", "es:rubber", "es:rubber"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "hazmat_suit:chestplate_hazmat",
|
|
||||||
recipe = {
|
|
||||||
{"es:purpellium_ingot", "dye:yellow", "es:purpellium_ingot"},
|
|
||||||
{"es:infinium_ingot", "es:purpellium_ingot", "es:infinium_ingot"},
|
|
||||||
{"es:purpellium_ingot", "es:infinium_ingot", "es:purpellium_ingot"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "hazmat_suit:sleeve_hazmat",
|
|
||||||
recipe = {
|
|
||||||
{"es:rubber", "dye:yellow"},
|
|
||||||
{"", "es:infinium_ingot"},
|
|
||||||
{"", "es:rubber"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "hazmat_suit:leggings_hazmat",
|
|
||||||
recipe = {
|
|
||||||
{"es:rubber", "es:purpellium_ingot", "es:rubber"},
|
|
||||||
{"es:infinium_ingot", "es:rubber", "es:infinium_ingot"},
|
|
||||||
{"es:purpellium_ingot", "", "es:purpellium_ingot"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "hazmat_suit:boots_hazmat",
|
|
||||||
recipe = {
|
|
||||||
{"", "", ""},
|
|
||||||
{"es:rubber", "", "es:rubber"},
|
|
||||||
{"es:infinium_ingot", "", "es:infinium_ingot"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "hazmat_suit:suit_hazmat",
|
|
||||||
type = "shapeless",
|
|
||||||
recipe = {
|
|
||||||
"hazmat_suit:helmet_hazmat",
|
|
||||||
"hazmat_suit:chestplate_hazmat",
|
|
||||||
"hazmat_suit:leggings_hazmat",
|
|
||||||
"hazmat_suit:boots_hazmat",
|
|
||||||
"hazmat_suit:sleeve_hazmat",
|
|
||||||
"hazmat_suit:sleeve_hazmat",
|
|
||||||
},
|
|
||||||
})
|
|
Before Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 160 B |
Before Width: | Height: | Size: 248 B |
Before Width: | Height: | Size: 189 B |
Before Width: | Height: | Size: 189 B |
Before Width: | Height: | Size: 302 B |
Before Width: | Height: | Size: 792 B |
Before Width: | Height: | Size: 1005 B |
10
mods/a_mapgen_mods/handle_schematics/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
This mod is not finished yet.
|
||||||
|
|
||||||
|
Create a file named
|
||||||
|
list_of_schematics.txt
|
||||||
|
in the folder containing this mod (not the world!).
|
||||||
|
Each line of the file ought to contain the name and full path to a schematic.
|
||||||
|
Those will be offered to you in the build chest's menu under "main".
|
||||||
|
|
||||||
|
Type "/giveme handle_schematics:build" to get a build chest.
|
@ -0,0 +1,215 @@
|
|||||||
|
|
||||||
|
-- This code is used to read Minecraft schematic files.
|
||||||
|
--
|
||||||
|
-- The .schematic file format is described here:
|
||||||
|
-- http://minecraft.gamepedia.com/Schematic_file_format?cookieSetup=true
|
||||||
|
-- It is based on the NBT format, which is described here:
|
||||||
|
-- http://minecraft.gamepedia.com/NBT_Format?cookieSetup=true
|
||||||
|
|
||||||
|
|
||||||
|
-- position in the decompressed string data_stream
|
||||||
|
local curr_index = 1;
|
||||||
|
|
||||||
|
-- helper arry so that the values do not have to be calculated anew each time
|
||||||
|
local pot256 = { 1 };
|
||||||
|
for i=1,8 do
|
||||||
|
pot256[ #pot256+1 ] = pot256[ #pot256 ] * 256;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- read length bytes from data_stream and turn it into an integer value
|
||||||
|
local read_signed = function( data_stream, length)
|
||||||
|
local res = 0;
|
||||||
|
for i=length,1,-1 do
|
||||||
|
res = res + (string.byte( data_stream, curr_index )* pot256[ i ]);
|
||||||
|
-- move one further
|
||||||
|
curr_index = curr_index+1;
|
||||||
|
end
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- this table will collect the few tags we're actually intrested in
|
||||||
|
local mc_schematic_data = {};
|
||||||
|
|
||||||
|
-- this will be a recursive function
|
||||||
|
local read_tag;
|
||||||
|
|
||||||
|
-- needs to be defined now because it will contain a recursive function
|
||||||
|
local read_one_tag;
|
||||||
|
|
||||||
|
-- read payload of one tag (= a data element in a NBT data structure)
|
||||||
|
read_one_tag = function( data_stream, tag, title_tag )
|
||||||
|
if( tag<= 0 or not(data_stream)) then
|
||||||
|
return;
|
||||||
|
elseif( tag==1 ) then -- TAG_BYTE: 1 byte
|
||||||
|
return read_signed( data_stream, 1 );
|
||||||
|
elseif( tag==2 ) then -- TAG_SHORT: 2 bytes
|
||||||
|
return read_signed( data_stream, 2 );
|
||||||
|
elseif( tag==3 ) then -- TAG_INT: 4 bytes
|
||||||
|
return read_signed( data_stream, 4 );
|
||||||
|
elseif( tag==4 ) then -- TAG_LONG: 8 bytes
|
||||||
|
return read_signed( data_stream, 8 );
|
||||||
|
elseif( tag==5 ) then -- TAG_FLOAT: 4 bytes
|
||||||
|
return read_signed( data_stream, 4 ); -- the float values are unused here
|
||||||
|
elseif( tag==6 ) then -- TAG_DOUBLE: 8 bytes
|
||||||
|
return read_signed( data_stream, 8 ); -- the float values are unused here
|
||||||
|
elseif( tag==7 ) then -- TAG_Byte_Array
|
||||||
|
local size = read_signed( data_stream, 4 ); -- TAG_INT
|
||||||
|
local res = {};
|
||||||
|
for i=1,size do
|
||||||
|
-- a Byte_Array does not contain any sub-tags
|
||||||
|
res[i] = read_one_tag( data_stream, 1, nil ); -- read TAG_BYTE
|
||||||
|
end
|
||||||
|
return res;
|
||||||
|
|
||||||
|
elseif( tag==8 ) then -- TAG_String
|
||||||
|
local size = read_signed( data_stream, 2);
|
||||||
|
local res = string.sub( data_stream, curr_index, curr_index+size-1 );
|
||||||
|
-- move on in the data stream
|
||||||
|
curr_index = curr_index + size;
|
||||||
|
return res;
|
||||||
|
|
||||||
|
elseif( tag==9 ) then -- TAG_List
|
||||||
|
-- these exact values are not particulary intresting
|
||||||
|
local tagtyp = read_signed( data_stream, 1 ); -- TAG_BYTE
|
||||||
|
local size = read_signed( data_stream, 4 ); -- TAG_INT
|
||||||
|
local res = {};
|
||||||
|
for i=1,size do
|
||||||
|
-- we need to pass title_tag on to the "child"
|
||||||
|
res[i] = read_one_tag( data_stream, tagtyp, title_tag );
|
||||||
|
end
|
||||||
|
return res;
|
||||||
|
|
||||||
|
elseif( tag==10 ) then -- TAG_Compound
|
||||||
|
return read_tag( data_stream, title_tag );
|
||||||
|
|
||||||
|
elseif( tag==11 ) then -- TAG_Int_Array
|
||||||
|
local size = read_signed( data_stream, 4 ); -- TAG_INT
|
||||||
|
local res = {};
|
||||||
|
for i=1,size do
|
||||||
|
-- a Int_Array does not contain any sub-tags
|
||||||
|
res[i] = read_one_tag( data_stream, 3, nil ); -- TAG_INT
|
||||||
|
end
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- read tag type, tag name and call read_one_tag to get the payload;
|
||||||
|
read_tag = function( data_stream, title_tag )
|
||||||
|
local schematic_data = {};
|
||||||
|
while( data_stream ) do
|
||||||
|
local tag = string.byte( data_stream, curr_index);
|
||||||
|
-- move on in the data stream
|
||||||
|
curr_index = curr_index + 1;
|
||||||
|
if( not( tag ) or tag <= 0 ) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
local tag_name_length = string.byte( data_stream, curr_index ) * 256 + string.byte(data_stream, curr_index + 1);
|
||||||
|
-- move 2 further
|
||||||
|
curr_index = curr_index + 2;
|
||||||
|
local tag_name = string.sub( data_stream, curr_index, curr_index+tag_name_length-1 );
|
||||||
|
-- move on...
|
||||||
|
curr_index = curr_index + tag_name_length;
|
||||||
|
--print('[analyze_mc_schematic_file] Found: Tag '..tostring( tag )..' <'..tostring( tag_name )..'>');
|
||||||
|
local res = read_one_tag( data_stream, tag, tag_name );
|
||||||
|
-- Entities and TileEntities are ignored
|
||||||
|
if( title_tag == 'Schematic'
|
||||||
|
and( tag_name == 'Width'
|
||||||
|
or tag_name == 'Height'
|
||||||
|
or tag_name == 'Length'
|
||||||
|
or tag_name == 'Materials' -- "Classic" or "Alpha" (=Survival)
|
||||||
|
or tag_name == 'Blocks'
|
||||||
|
or tag_name == 'Data'
|
||||||
|
)) then
|
||||||
|
mc_schematic_data[ tag_name ] = res;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
handle_schematics.analyze_mc_schematic_file = function( path )
|
||||||
|
-- these files are usually compressed; there is no point to start if the
|
||||||
|
-- decompress function is missing
|
||||||
|
if( minetest.decompress == nil) then
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
|
||||||
|
local file, err = save_restore.file_access(path..'.schematic', "rb")
|
||||||
|
if (file == nil) then
|
||||||
|
-- print('[analyze_mc_schematic_file] ERROR: NO such file: '..tostring( path..'.schematic'));
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local compressed_data = file:read( "*all" );
|
||||||
|
--local data_string = minetest.decompress(compressed_data, "deflate" );
|
||||||
|
local data_string = compressed_data; -- TODO
|
||||||
|
print('FILE SIZE: '..tostring( string.len( data_string ))); -- TODO
|
||||||
|
file.close(file)
|
||||||
|
|
||||||
|
|
||||||
|
-- we use this (to this file) global variable to store gathered information;
|
||||||
|
-- doing so inside the recursive functions proved problematic
|
||||||
|
mc_schematic_data = {};
|
||||||
|
-- this index will iterate through the schematic data
|
||||||
|
curr_index = 1;
|
||||||
|
-- actually analyze the data
|
||||||
|
read_tag( data_string, nil );
|
||||||
|
|
||||||
|
if( not( mc_schematic_data.Width )
|
||||||
|
or not( mc_schematic_data.Height )
|
||||||
|
or not( mc_schematic_data.Length )
|
||||||
|
or not( mc_schematic_data.Blocks )
|
||||||
|
or not( mc_schematic_data.Data )) then
|
||||||
|
print('[analyze_mc_schematic_file] ERROR: Failed to analyze '..tostring( path..'.schematic'));
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
|
||||||
|
local translation_function = handle_schematics.findMC2MTConversion;
|
||||||
|
if( minetest.get_modpath('mccompat')) then
|
||||||
|
translation_function = mccompat.findMC2MTConversion;
|
||||||
|
end
|
||||||
|
|
||||||
|
local max_msg = 40; -- just for error handling
|
||||||
|
local size = {x=mc_schematic_data.Width, y=mc_schematic_data.Height, z=mc_schematic_data.Length};
|
||||||
|
local scm = {};
|
||||||
|
local nodenames = {};
|
||||||
|
local nodenames_id = {};
|
||||||
|
for y=1,size.y do
|
||||||
|
scm[y] = {};
|
||||||
|
for x=1,size.x do
|
||||||
|
scm[y][x] = {};
|
||||||
|
for z =1,size.z do
|
||||||
|
local new_node = translation_function(
|
||||||
|
-- (Y×length + Z)×width + X.
|
||||||
|
mc_schematic_data.Blocks[ ((y-1)*size.z + (z-1) )*size.x + (size.x-x) +1],
|
||||||
|
mc_schematic_data.Data[ ((y-1)*size.z + (z-1) )*size.x + (size.x-x) +1] );
|
||||||
|
-- some MC nodes store the information about a node in TWO block and data fields (doors, large flowers, ...)
|
||||||
|
if( new_node[3] and new_node[3]~=0 ) then
|
||||||
|
new_node = translation_function(
|
||||||
|
-- (Y×length + Z)×width + X.
|
||||||
|
mc_schematic_data.Blocks[ ((y-1)*size.z + (z-1) )*size.x + (size.x-x) +1],
|
||||||
|
mc_schematic_data.Data[ ((y-1)*size.z + (z-1) )*size.x + (size.x-x) +1],
|
||||||
|
mc_schematic_data.Blocks[ ((y-1+new_node[3])*size.z + (z-1) )*size.x + (size.x-x) +1],
|
||||||
|
mc_schematic_data.Data[ ((y-1+new_node[3])*size.z + (z-1) )*size.x + (size.x-x) +1] );
|
||||||
|
end
|
||||||
|
if( not( nodenames_id[ new_node[1]] )) then
|
||||||
|
nodenames_id[ new_node[1] ] = #nodenames + 1;
|
||||||
|
nodenames[ nodenames_id[ new_node[1] ]] = new_node[1];
|
||||||
|
end
|
||||||
|
-- print a few warning messages in case something goes wrong - but do not exaggerate
|
||||||
|
if( not( new_node[2] and max_msg>0)) then
|
||||||
|
-- print('[handle_schematics:schematic] MISSING param2: '..minetest.serialize( new_node ));
|
||||||
|
new_node[2]=0;
|
||||||
|
max_msg=max_msg-1;
|
||||||
|
end
|
||||||
|
-- save some space by not saving air
|
||||||
|
if( new_node[1] ~= 'air' ) then
|
||||||
|
scm[y][x][z] = { nodenames_id[ new_node[1]], new_node[2]};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return { size = { x=size.x, y=size.y, z=size.z}, nodenames = nodenames, on_constr = {}, after_place_node = {}, rotated=90, burried=0, scm_data_cache = scm, metadata = {}};
|
||||||
|
end
|
||||||
|
|
279
mods/a_mapgen_mods/handle_schematics/analyze_mts_file.lua
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
|
||||||
|
--[[ taken from src/mg_schematic.cpp:
|
||||||
|
Minetest Schematic File Format
|
||||||
|
|
||||||
|
All values are stored in big-endian byte order.
|
||||||
|
[u32] signature: 'MTSM'
|
||||||
|
[u16] version: 3
|
||||||
|
[u16] size X
|
||||||
|
[u16] size Y
|
||||||
|
[u16] size Z
|
||||||
|
For each Y:
|
||||||
|
[u8] slice probability value
|
||||||
|
[Name-ID table] Name ID Mapping Table
|
||||||
|
[u16] name-id count
|
||||||
|
For each name-id mapping:
|
||||||
|
[u16] name length
|
||||||
|
[u8[] ] name
|
||||||
|
ZLib deflated {
|
||||||
|
For each node in schematic: (for z, y, x)
|
||||||
|
[u16] content
|
||||||
|
For each node in schematic:
|
||||||
|
[u8] probability of occurance (param1)
|
||||||
|
For each node in schematic:
|
||||||
|
[u8] param2
|
||||||
|
}
|
||||||
|
|
||||||
|
Version changes:
|
||||||
|
1 - Initial version
|
||||||
|
2 - Fixed messy never/always place; 0 probability is now never, 0xFF is always
|
||||||
|
3 - Added y-slice probabilities; this allows for variable height structures
|
||||||
|
--]]
|
||||||
|
|
||||||
|
--handle_schematics = {}
|
||||||
|
|
||||||
|
-- taken from https://github.com/MirceaKitsune/minetest_mods_structures/blob/master/structures_io.lua (Taokis Sructures I/O mod)
|
||||||
|
-- gets the size of a structure file
|
||||||
|
-- nodenames: contains all the node names that are used in the schematic
|
||||||
|
-- on_constr: lists all the node names for which on_construct has to be called after placement of the schematic
|
||||||
|
handle_schematics.analyze_mts_file = function( path )
|
||||||
|
local size = { x = 0, y = 0, z = 0, version = 0 }
|
||||||
|
local version = 0;
|
||||||
|
|
||||||
|
local file, err = save_restore.file_access(path..'.mts', "rb")
|
||||||
|
if (file == nil) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
--print('[handle_schematics] Analyzing .mts file '..tostring( path..'.mts' ));
|
||||||
|
--if( not( string.byte )) then
|
||||||
|
-- print( '[handle_schematics] Error: string.byte undefined.');
|
||||||
|
-- return nil;
|
||||||
|
--end
|
||||||
|
|
||||||
|
-- thanks to sfan5 for this advanced code that reads the size from schematic files
|
||||||
|
local read_s16 = function(fi)
|
||||||
|
return string.byte(fi:read(1)) * 256 + string.byte(fi:read(1))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_schematic_size(f)
|
||||||
|
-- make sure those are the first 4 characters, otherwise this might be a corrupt file
|
||||||
|
if f:read(4) ~= "MTSM" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
-- advance 2 more characters
|
||||||
|
local version = read_s16(f); --f:read(2)
|
||||||
|
-- the next characters here are our size, read them
|
||||||
|
return read_s16(f), read_s16(f), read_s16(f), version
|
||||||
|
end
|
||||||
|
|
||||||
|
size.x, size.y, size.z, size.version = get_schematic_size(file)
|
||||||
|
|
||||||
|
-- read the slice probability for each y value that was introduced in version 3
|
||||||
|
if( size.version >= 3 ) then
|
||||||
|
-- the probability is not very intresting for buildings so we just skip it
|
||||||
|
file:read( size.y );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- this list is not yet used for anything
|
||||||
|
local nodenames = {};
|
||||||
|
-- this list is needed for calling on_construct after place_schematic
|
||||||
|
local on_constr = {};
|
||||||
|
-- nodes that require after_place_node to be called
|
||||||
|
local after_place_node = {};
|
||||||
|
|
||||||
|
-- after that: read_s16 (2 bytes) to find out how many diffrent nodenames (node_name_count) are present in the file
|
||||||
|
local node_name_count = read_s16( file );
|
||||||
|
|
||||||
|
for i = 1, node_name_count do
|
||||||
|
|
||||||
|
-- the length of the next name
|
||||||
|
local name_length = read_s16( file );
|
||||||
|
-- the text of the next name
|
||||||
|
local name_text = file:read( name_length );
|
||||||
|
|
||||||
|
table.insert( nodenames, name_text );
|
||||||
|
-- in order to get this information, the node has to be defined and loaded
|
||||||
|
if( minetest.registered_nodes[ name_text ] and minetest.registered_nodes[ name_text ].on_construct) then
|
||||||
|
table.insert( on_constr, name_text );
|
||||||
|
end
|
||||||
|
-- some nodes need after_place_node to be called for initialization
|
||||||
|
if( minetest.registered_nodes[ name_text ] and minetest.registered_nodes[ name_text ].after_place_node) then
|
||||||
|
table.insert( after_place_node, name_text );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local rotated = 0;
|
||||||
|
local burried = 0;
|
||||||
|
local parts = path:split('_');
|
||||||
|
if( parts and #parts > 2 ) then
|
||||||
|
if( parts[#parts]=="0" or parts[#parts]=="90" or parts[#parts]=="180" or parts[#parts]=="270" ) then
|
||||||
|
rotated = tonumber( parts[#parts] );
|
||||||
|
burried = tonumber( parts[ #parts-1 ] );
|
||||||
|
if( not( burried ) or burried>20 or burried<0) then
|
||||||
|
burried = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- decompression was recently added; if it is not yet present, we need to use normal place_schematic
|
||||||
|
if( minetest.decompress == nil) then
|
||||||
|
file.close(file);
|
||||||
|
return nil; -- normal place_schematic is no longer supported as minetest.decompress is now part of the release version of minetest
|
||||||
|
-- return { size = { x=size.x, y=size.y, z=size.z}, nodenames = nodenames, on_constr = on_constr, after_place_node = after_place_node, rotated=rotated, burried=burried, scm_data_cache = nil };
|
||||||
|
end
|
||||||
|
|
||||||
|
local compressed_data = file:read( "*all" );
|
||||||
|
local data_string = minetest.decompress(compressed_data, "deflate" );
|
||||||
|
file.close(file)
|
||||||
|
|
||||||
|
local ids = {};
|
||||||
|
local needs_on_constr = {};
|
||||||
|
local is_air = 0;
|
||||||
|
-- translate nodenames to ids
|
||||||
|
for i,v in ipairs( nodenames ) do
|
||||||
|
ids[ i ] = minetest.get_content_id( v );
|
||||||
|
needs_on_constr[ i ] = false;
|
||||||
|
if( minetest.registered_nodes[ v ] and minetest.registered_nodes[ v ].on_construct ) then
|
||||||
|
needs_on_constr[ i ] = true;
|
||||||
|
end
|
||||||
|
if( v == 'air' ) then
|
||||||
|
is_air = i;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local p2offset = (size.x*size.y*size.z)*3;
|
||||||
|
local i = 1;
|
||||||
|
local scm = {};
|
||||||
|
for z = 1, size.z do
|
||||||
|
for y = 1, size.y do
|
||||||
|
for x = 1, size.x do
|
||||||
|
if( not( scm[y] )) then
|
||||||
|
scm[y] = {};
|
||||||
|
end
|
||||||
|
if( not( scm[y][x] )) then
|
||||||
|
scm[y][x] = {};
|
||||||
|
end
|
||||||
|
local id = string.byte( data_string, i ) * 256 + string.byte( data_string, i+1 );
|
||||||
|
i = i + 2;
|
||||||
|
local p2 = string.byte( data_string, p2offset + math.floor(i/2));
|
||||||
|
id = id+1;
|
||||||
|
|
||||||
|
if( id ~= is_air ) then
|
||||||
|
scm[y][x][z] = {id, p2};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { size = { x=size.x, y=size.y, z=size.z}, nodenames = nodenames, on_constr = on_constr, after_place_node = after_place_node, rotated=rotated, burried=burried, scm_data_cache = scm };
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
handle_schematics.store_mts_file = function( path, data )
|
||||||
|
|
||||||
|
data.nodenames[ #data.nodenames+1 ] = 'air';
|
||||||
|
|
||||||
|
local file, err = save_restore.file_access(path..'.mts', "wb")
|
||||||
|
if (file == nil) then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local write_s16 = function( fi, a )
|
||||||
|
fi:write( string.char( math.floor( a/256) ));
|
||||||
|
fi:write( string.char( a%256 ));
|
||||||
|
end
|
||||||
|
|
||||||
|
data.size.version = 3; -- we only support version 3 of the .mts file format
|
||||||
|
|
||||||
|
file:write( "MTSM" );
|
||||||
|
write_s16( file, data.size.version );
|
||||||
|
write_s16( file, data.size.x );
|
||||||
|
write_s16( file, data.size.y );
|
||||||
|
write_s16( file, data.size.z );
|
||||||
|
|
||||||
|
|
||||||
|
-- set the slice probability for each y value that was introduced in version 3
|
||||||
|
if( data.size.version >= 3 ) then
|
||||||
|
-- the probability is not very intresting for buildings so we just skip it
|
||||||
|
for i=1,data.size.y do
|
||||||
|
file:write( string.char(255) );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set how many diffrent nodenames (node_name_count) are present in the file
|
||||||
|
write_s16( file, #data.nodenames );
|
||||||
|
|
||||||
|
for i = 1, #data.nodenames do
|
||||||
|
-- the length of the next name
|
||||||
|
write_s16( file, string.len( data.nodenames[ i ] ));
|
||||||
|
file:write( data.nodenames[ i ] );
|
||||||
|
end
|
||||||
|
|
||||||
|
-- this string will later be compressed
|
||||||
|
local node_data = "";
|
||||||
|
|
||||||
|
-- actual node data
|
||||||
|
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];
|
||||||
|
if( a and type( a ) == 'table') then
|
||||||
|
node_data = node_data..string.char( math.floor( a[1]/256) )..string.char( a[1]%256-1);
|
||||||
|
else
|
||||||
|
node_data = node_data..string.char( 0 )..string.char( #data.nodenames-1 );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- probability of occurance
|
||||||
|
for z = 1, data.size.z do
|
||||||
|
for y = 1, data.size.y do
|
||||||
|
for x = 1, data.size.x do
|
||||||
|
node_data = node_data..string.char( 255 );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- param2
|
||||||
|
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];
|
||||||
|
if( a and type( a) == 'table' ) then
|
||||||
|
node_data = node_data..string.char( a[2] );
|
||||||
|
else
|
||||||
|
node_data = node_data..string.char( 0 );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local compressed_data = minetest.compress( node_data, "deflate" );
|
||||||
|
file:write( compressed_data );
|
||||||
|
file.close(file);
|
||||||
|
print('SAVING '..path..'.mts (converted from .we).');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- read .mts and .we files
|
||||||
|
handle_schematics.analyze_file = function( file_name, origin_offset, store_as_mts )
|
||||||
|
local res = handle_schematics.analyze_mts_file( file_name );
|
||||||
|
-- alternatively, read the mts file
|
||||||
|
if( not( res )) then
|
||||||
|
res = handle_schematics.analyze_we_file( file_name, origin_offset );
|
||||||
|
if( not( res )) then
|
||||||
|
res = handle_schematics.analyze_mc_schematic_file( file_name );
|
||||||
|
end
|
||||||
|
-- print error message only if all import methods failed
|
||||||
|
if( not( res )) then
|
||||||
|
print('[handle_schematics] ERROR: Failed to import file \"'..tostring( file_name )..'\"[.mts|.we|.wem|.schematic]');
|
||||||
|
-- convert to .mts for later usage
|
||||||
|
elseif( store_as_mts ) then
|
||||||
|
handle_schematics.store_mts_file( store_as_mts, res );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return res;
|
||||||
|
end
|
100
mods/a_mapgen_mods/handle_schematics/analyze_we_file.lua
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
handle_schematics.analyze_we_file = function(scm, we_origin)
|
||||||
|
local c_ignore = minetest.get_content_id("ignore")
|
||||||
|
|
||||||
|
-- this table will contain the nodes read
|
||||||
|
local nodes = {}
|
||||||
|
|
||||||
|
-- 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 = save_restore.file_access( scm..".we", "r")
|
||||||
|
if not f then
|
||||||
|
f, err = save_restore.file_access( scm..".wem", "r")
|
||||||
|
if not f then
|
||||||
|
-- error("Could not open schematic '" .. scm .. ".we': " .. err)
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local value = f:read("*a")
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
local nodes = worldedit_file.load_schematic(value, we_origin)
|
||||||
|
|
||||||
|
-- create a list of nodenames
|
||||||
|
local nodenames = {};
|
||||||
|
local nodenames_id = {};
|
||||||
|
for i,ent in ipairs( nodes ) do
|
||||||
|
if( ent and ent.name and not( nodenames_id[ ent.name ])) then
|
||||||
|
nodenames_id[ ent.name ] = #nodenames + 1;
|
||||||
|
nodenames[ nodenames_id[ ent.name ] ] = ent.name;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scm = {}
|
||||||
|
local maxx, maxy, maxz = -1, -1, -1
|
||||||
|
local all_meta = {};
|
||||||
|
for i = 1, #nodes do
|
||||||
|
local ent = nodes[i]
|
||||||
|
ent.x = ent.x + 1
|
||||||
|
ent.y = ent.y + 1
|
||||||
|
ent.z = ent.z + 1
|
||||||
|
if ent.x > maxx then
|
||||||
|
maxx = ent.x
|
||||||
|
end
|
||||||
|
if ent.y > maxy then
|
||||||
|
maxy = ent.y
|
||||||
|
end
|
||||||
|
if ent.z > maxz then
|
||||||
|
maxz = ent.z
|
||||||
|
end
|
||||||
|
if scm[ent.y] == nil then
|
||||||
|
scm[ent.y] = {}
|
||||||
|
end
|
||||||
|
if scm[ent.y][ent.x] == nil then
|
||||||
|
scm[ent.y][ent.x] = {}
|
||||||
|
end
|
||||||
|
if ent.param2 == nil then
|
||||||
|
ent.param2 = 0
|
||||||
|
end
|
||||||
|
-- metadata is only of intrest if it is not empty
|
||||||
|
if( ent.meta and (ent.meta.fields or ent.meta.inventory)) then
|
||||||
|
local has_meta = false;
|
||||||
|
for _,v in pairs( ent.meta.fields ) do
|
||||||
|
has_meta = true;
|
||||||
|
end
|
||||||
|
for _,v in pairs(ent.meta.inventory) do
|
||||||
|
has_meta = true;
|
||||||
|
end
|
||||||
|
if( has_meta == true ) then
|
||||||
|
all_meta[ #all_meta+1 ] = {
|
||||||
|
x=ent.x,
|
||||||
|
y=ent.y,
|
||||||
|
z=ent.z,
|
||||||
|
fields = ent.meta.fields,
|
||||||
|
inventory = ent.meta.inventory};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
scm[ent.y][ent.x][ent.z] = { nodenames_id[ ent.name ], ent.param2 };
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
for y = 1, maxy do
|
||||||
|
if scm[y] == nil then
|
||||||
|
scm[y] = {}
|
||||||
|
end
|
||||||
|
for x = 1, maxx do
|
||||||
|
if scm[y][x] == nil then
|
||||||
|
scm[y][x] = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local size = {};
|
||||||
|
size.y = math.max(maxy,0);
|
||||||
|
size.x = math.max(maxx,0);
|
||||||
|
size.z = math.max(maxz,0);
|
||||||
|
|
||||||
|
return { size = { x=size.x, y=size.y, z=size.z}, nodenames = nodenames, on_constr = {}, after_place_node = {}, rotated=0, burried=0, scm_data_cache = scm, metadata = all_meta };
|
||||||
|
end
|
876
mods/a_mapgen_mods/handle_schematics/build_chest.lua
Normal file
@ -0,0 +1,876 @@
|
|||||||
|
-----------------------------------------------------------------------------------------------------------------
|
||||||
|
-- interface for manual placement of houses
|
||||||
|
-----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
-- add a menu entry that will always be available
|
||||||
|
build_chest.add_entry( {'save a building'} );
|
||||||
|
|
||||||
|
-- needed for saving buildings
|
||||||
|
build_chest.end_pos_list = {};
|
||||||
|
|
||||||
|
--dofile( minetest.get_modpath( minetest.get_current_modname()).."/build_chest_handle_replacements.lua");
|
||||||
|
--dofile( minetest.get_modpath( minetest.get_current_modname()).."/build_chest_preview_image.lua");
|
||||||
|
--dofile( minetest.get_modpath( minetest.get_current_modname()).."/build_chest_add_schems.lua");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.read_building = function( building_name )
|
||||||
|
-- read data
|
||||||
|
local res = handle_schematics.analyze_file( building_name, nil, nil );
|
||||||
|
if( not( res )) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
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;
|
||||||
|
build_chest.building[ building_name ].metadata = res.metadata;
|
||||||
|
-- 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 = handle_schematics.count_nodes( res );
|
||||||
|
|
||||||
|
build_chest.building[ building_name ].preview = build_chest.preview_image_create_views( res,
|
||||||
|
build_chest.building[ building_name ].orients );
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.get_start_pos = function( pos )
|
||||||
|
-- rotate the building so that it faces the player
|
||||||
|
local node = minetest.get_node( pos );
|
||||||
|
local meta = minetest.get_meta( pos );
|
||||||
|
|
||||||
|
local building_name = meta:get_string( 'building_name' );
|
||||||
|
if( not( building_name )) then
|
||||||
|
return "No building_name provided.";
|
||||||
|
end
|
||||||
|
if( not( build_chest.building[ building_name ] )) then
|
||||||
|
return "No data found for this building.";
|
||||||
|
end
|
||||||
|
|
||||||
|
if( not( build_chest.building[ building_name ].size )) then
|
||||||
|
if( not( build_chest.read_building( building_name ))) then
|
||||||
|
return "Unable to read data file of this building.";
|
||||||
|
end
|
||||||
|
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,
|
||||||
|
selected_building.yoff );
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.show_size_data = function( building_name )
|
||||||
|
|
||||||
|
if( not( building_name )
|
||||||
|
or building_name == ''
|
||||||
|
or not( build_chest.building[ building_name ] )
|
||||||
|
or not( build_chest.building[ building_name ].size )) then
|
||||||
|
return "";
|
||||||
|
end
|
||||||
|
|
||||||
|
local size = build_chest.building[ building_name ].size;
|
||||||
|
-- show which building has been selected
|
||||||
|
return "label[0.3,9.5;Selected building:]"..
|
||||||
|
"label[2.3,9.5;"..minetest.formspec_escape(building_name).."]"..
|
||||||
|
-- size of the building
|
||||||
|
"label[0.3,9.8;Size ( wide x length x height ):]"..
|
||||||
|
"label[4.3,9.8;"..tostring( size.x )..' x '..tostring( size.z )..' x '..tostring( size.y ).."]";
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- helper function for update_formspec that handles saving of a building
|
||||||
|
handle_schematics.update_formspec_save_building = function( formspec, meta, player, fields, pos )
|
||||||
|
local saved_as_filename = meta:get_string('saved_as_filename');
|
||||||
|
if( saved_as_filename and saved_as_filename ~= "" ) then
|
||||||
|
local p1str = meta:get_string('p1');
|
||||||
|
local p2str = meta:get_string('p2');
|
||||||
|
|
||||||
|
return formspec..
|
||||||
|
"label[2.0,3;This area has been saved to the file]"..
|
||||||
|
"label[2.5,3.3;"..minetest.formspec_escape( saved_as_filename ).."]"..
|
||||||
|
"label[2.0,3.6;The area extends from]"..
|
||||||
|
"label[2.5,3.9;"..minetest.formspec_escape( p1str ).."]"..
|
||||||
|
"label[2.0,4.2;to the point]"..
|
||||||
|
"label[2.5,4.5;"..minetest.formspec_escape( p2str ).."]"..
|
||||||
|
"button[5,8.0;3,0.5;back;Back]";
|
||||||
|
end
|
||||||
|
|
||||||
|
local end_pos_mark = build_chest.end_pos_list[ player:get_player_name() ];
|
||||||
|
if( end_pos_mark
|
||||||
|
and end_pos_mark.x==pos.x
|
||||||
|
and end_pos_mark.y==pos.y
|
||||||
|
and end_pos_mark.z==pos.z ) then
|
||||||
|
|
||||||
|
return formspec..
|
||||||
|
"label[2,3.0;This chest marks the end position of your building. Please put another]"..
|
||||||
|
"label[2,3.3;build chest in front of your building and save it with that chest.]"..
|
||||||
|
"button[5,8.0;3,0.5;back;Back]";
|
||||||
|
end
|
||||||
|
|
||||||
|
if( end_pos_mark and end_pos_mark.start_pos ) then
|
||||||
|
|
||||||
|
if( end_pos_mark.start_pos.x == pos.x
|
||||||
|
and end_pos_mark.start_pos.y == pos.y
|
||||||
|
and end_pos_mark.start_pos.z == pos.z ) then
|
||||||
|
local p2 = {x=end_pos_mark.x, y=end_pos_mark.y, z=end_pos_mark.z};
|
||||||
|
local p1 = {x=end_pos_mark.start_pos.x, y=end_pos_mark.start_pos.y, z=end_pos_mark.start_pos.z};
|
||||||
|
local height = math.abs( p1.y - p2.y )+1;
|
||||||
|
local width = 0;
|
||||||
|
local length = 0;
|
||||||
|
if( end_pos_mark.param2==0 or end_pos_mark.param2==2 ) then
|
||||||
|
-- adjust p1 and p2 so that only the area we really care about is marked
|
||||||
|
if( p1.z > p2.z ) then
|
||||||
|
p1.z = p1.z-1;
|
||||||
|
p2.z = p2.z+1;
|
||||||
|
else
|
||||||
|
p1.z = p1.z+1;
|
||||||
|
p2.z = p2.z-1;
|
||||||
|
end
|
||||||
|
width = math.abs( p1.x - p2.x )+1;
|
||||||
|
length = math.abs( p1.z - p2.z )+1;
|
||||||
|
else
|
||||||
|
if( p1.x > p2.x ) then
|
||||||
|
p1.x = p1.x-1;
|
||||||
|
p2.x = p2.x+1;
|
||||||
|
else
|
||||||
|
p1.x = p1.x+1;
|
||||||
|
p2.x = p2.x-1;
|
||||||
|
end
|
||||||
|
length = math.abs( p1.x - p2.x )+1;
|
||||||
|
width = math.abs( p1.z - p2.z )+1;
|
||||||
|
end
|
||||||
|
return formspec..
|
||||||
|
-- p1 and p2 are passed on as inputs in order to avoid any unwanted future interferences
|
||||||
|
-- with any other build chests
|
||||||
|
"field[40,40;0.1,0.1;save_as_p1;;"..minetest.pos_to_string(p1).."]"..
|
||||||
|
"field[40,40;0.1,0.1;save_as_p2;;"..minetest.pos_to_string(p2).."]"..
|
||||||
|
|
||||||
|
"label[2,2.4;How high is your building? This does *not* include the height offset below. The]"..
|
||||||
|
"label[2,2.7;default value is calculated from the height difference between start and end position.]"..
|
||||||
|
"label[2,3.15;Total height of your building:]"..
|
||||||
|
"field[6,3.5;1,0.5;save_as_height;;"..tostring(height).."]"..
|
||||||
|
|
||||||
|
-- note: in mg_villages, yoff has to be 0 in order to include the ground floor as well;
|
||||||
|
-- "1" means the building without floor; here, "1" means a floating building
|
||||||
|
"label[2,3.8;The hight offset sets how deep your building will be burried in the ground. Examples:]"..
|
||||||
|
"label[2.5,4.1;A value of -4 will include a cellar which extends 4 nodes below this build chest.]"..
|
||||||
|
"label[2.5,4.4;A value of -1 will include the floor below the chest, but no cellar.]"..
|
||||||
|
"label[2.5,4.7;A positive value will make your building float in the air.]"..
|
||||||
|
"label[2,5.15;Add height offset:]"..
|
||||||
|
"field[6,5.5;1,0.5;save_as_yoff;;0]"..
|
||||||
|
|
||||||
|
"label[2,5.8;Without the changes entered in the input form above, your building will extend from]"..
|
||||||
|
"label[2.5,6.1;"..minetest.formspec_escape(
|
||||||
|
minetest.pos_to_string( p1 ).." to "..
|
||||||
|
minetest.pos_to_string( p2 ).." and span a volume of "..
|
||||||
|
-- x and z are swpapped here if rotated by 90 or 270 degree
|
||||||
|
tostring(width )..' (width) x '..
|
||||||
|
tostring(length)..' (depth) x '..
|
||||||
|
tostring(height)..' (height)').."]"..
|
||||||
|
|
||||||
|
"label[2,6.7;Please enter a descriptive filename. Allowed charcters: "..
|
||||||
|
minetest.formspec_escape("a-z, A-Z, 0-9, -, _, .").."]"..
|
||||||
|
"label[2,7.15;Save schematic as:]"..
|
||||||
|
"field[6,7.5;4,0.5;save_as_filename;;]"..
|
||||||
|
|
||||||
|
"button[2,8.0;3,0.5;abort_set_start_pos;Abort]"..
|
||||||
|
"button[6,8.0;3,0.5;save_as;Save building now]";
|
||||||
|
else
|
||||||
|
return formspec..
|
||||||
|
"label[3,3;You have selected another build chest as start position.]"..
|
||||||
|
"button[5,8.0;3,0.5;back;Back]"..
|
||||||
|
"button[5,5.0;3,0.5;abort_set_start_pos;Reset start position]";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if( fields.error_msg ) then
|
||||||
|
return formspec..
|
||||||
|
"label[4,4.5;Error while trying to set the start position:]"..
|
||||||
|
"textarea[4,5;6,2;error_msg;;"..
|
||||||
|
minetest.formspec_escape( fields.error_msg ).."]"..
|
||||||
|
"button[5,8.0;3,0.5;back;Back]";
|
||||||
|
end
|
||||||
|
|
||||||
|
return formspec..
|
||||||
|
"label[2.5,2.2;First, let us assume that you are facing the front of this build chest.]"..
|
||||||
|
|
||||||
|
"label[2,3.1;Are you looking at the BACKSIDE of your building, and does said backside stretch]"..
|
||||||
|
"label[2,3.4;to the right and in front of you? Then click on the button below:]"..
|
||||||
|
"button[4,4;5,0.5;set_end_pos;Set this position as new end position]"..
|
||||||
|
|
||||||
|
"label[2,5.2;Have you set the end position with another build chest using the method above]"..
|
||||||
|
"label[2,5.5;in the meantime? And are you now looking at the FRONT of your building, which]"..
|
||||||
|
"label[2,5.8;streches in front of you and to the right? Then click on Proceed:]"..
|
||||||
|
"button[5,6.4;3,0.5;set_start_pos;Proceed with saving]"..
|
||||||
|
|
||||||
|
"label[4,7.4;If this confuses you, you can also abort the process.]"..
|
||||||
|
"button[5,8.0;3,0.5;back;Abort]";
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.update_formspec = function( pos, page, player, fields )
|
||||||
|
|
||||||
|
-- information about the village the build chest may belong to and about the owner
|
||||||
|
local meta = minetest.get_meta( pos );
|
||||||
|
local village_name = meta:get_string( 'village' );
|
||||||
|
local village_pos = minetest.deserialize( meta:get_string( 'village_pos' ));
|
||||||
|
local owner_name = meta:get_string( 'owner' );
|
||||||
|
local building_name = meta:get_string('building_name' );
|
||||||
|
|
||||||
|
-- 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 ) ));
|
||||||
|
|
||||||
|
-- the statistic is needed for all the replacements later on as it also contains the list of nodenames
|
||||||
|
if( building_name and building_name~=""and not( build_chest.building[ building_name ].size )) then
|
||||||
|
build_chest.read_building( building_name );
|
||||||
|
end
|
||||||
|
|
||||||
|
if( page == 'please_remove' ) then
|
||||||
|
if( build_chest.stages_formspec_page_please_remove ) then
|
||||||
|
return build_chest.stages_formspec_page_please_remove( building_name, owner_name, village_name, village_pos, distance );
|
||||||
|
end
|
||||||
|
elseif( page == 'finished' ) then
|
||||||
|
if( build_chest.stages_formspec_page_finished ) then
|
||||||
|
return build_chest.stages_formspec_page_finished( building_name, owner_name, village_name, village_pos, distance );
|
||||||
|
end
|
||||||
|
elseif( page ~= 'main' ) then
|
||||||
|
-- if in doubt, return the old formspec
|
||||||
|
return meta:get_string('formspec');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- create the header
|
||||||
|
local formspec = "size[13,10]"..
|
||||||
|
"label[3.3,0.0;Building box]"..
|
||||||
|
"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:]"..
|
||||||
|
build_chest.show_size_data( building_name );
|
||||||
|
|
||||||
|
local current_path = minetest.deserialize( meta:get_string( 'current_path' ) or 'return {}' );
|
||||||
|
if( #current_path > 0 ) then
|
||||||
|
formspec = formspec.."button[9.9,0.4;2,0.5;back;Back]";
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- offer a menu to set the positions for saving a building
|
||||||
|
if( #current_path > 0 and current_path[1]=='save a building' ) then
|
||||||
|
return handle_schematics.update_formspec_save_building( formspec, meta, player, fields, pos);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- the building has been placed; offer to restore a backup
|
||||||
|
local backup_file = meta:get_string('backup');
|
||||||
|
if( backup_file and backup_file ~= "" ) then
|
||||||
|
return formspec.."button[3,3;3,0.5;restore_backup;Restore original landscape]";
|
||||||
|
end
|
||||||
|
|
||||||
|
-- offer diffrent replacement groups
|
||||||
|
if( fields.set_wood and fields.set_wood ~= "" ) then
|
||||||
|
return formspec..
|
||||||
|
"label[1,2.2;Select replacement for "..tostring( fields.set_wood )..".]"..
|
||||||
|
"label[1,2.5;Trees, saplings and other blocks will be replaced accordingly as well.]"..
|
||||||
|
-- invisible field that encodes the value given here
|
||||||
|
"field[-20,-20;0.1,0.1;set_wood;;"..minetest.formspec_escape( fields.set_wood ).."]"..
|
||||||
|
build_chest.replacements_get_group_list_formspec( pos, 'wood', 'wood_selection' );
|
||||||
|
end
|
||||||
|
|
||||||
|
if( fields.set_farming and fields.set_farming ~= "" ) then
|
||||||
|
return formspec..
|
||||||
|
"label[1,2.5;Select the fruit the farm is going to grow:]"..
|
||||||
|
-- invisible field that encodes the value given here
|
||||||
|
"field[-20,-20;0.1,0.1;set_farming;;"..minetest.formspec_escape( fields.set_farming ).."]"..
|
||||||
|
build_chest.replacements_get_group_list_formspec( pos, 'farming', 'farming_selection' );
|
||||||
|
end
|
||||||
|
|
||||||
|
if( fields.set_roof and fields.set_roof ~= "" ) then
|
||||||
|
return formspec..
|
||||||
|
"label[1,2.5;Select a roof type for the house:]"..
|
||||||
|
-- invisible field that encodes the value given here
|
||||||
|
"field[-20,-20;0.1,0.1;set_roof;;"..minetest.formspec_escape( fields.set_roof ).."]"..
|
||||||
|
build_chest.replacements_get_group_list_formspec( pos, 'roof', 'roof_selection' );
|
||||||
|
end
|
||||||
|
|
||||||
|
if( fields.preview and building_name ) then
|
||||||
|
return formspec..build_chest.preview_image_formspec( building_name,
|
||||||
|
minetest.deserialize( meta:get_string( 'replacements' )), fields.preview);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- show list of all node names used
|
||||||
|
local start_pos = meta:get_string('start_pos');
|
||||||
|
if( building_name and building_name ~= '' and start_pos and start_pos ~= '' and meta:get_string('replacements')) then
|
||||||
|
return formspec..build_chest.replacements_get_list_formspec( pos );
|
||||||
|
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
|
||||||
|
|
||||||
|
-- handle if there are multiple files under the same menu point
|
||||||
|
if( #options == 0 and build_chest.building[ current_path[#current_path]] ) then
|
||||||
|
options = {current_path[#current_path]};
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we have found an end-node - a particular building
|
||||||
|
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( type(start_pos)=='table' and start_pos and start_pos.x and build_chest.building[ options[1]].size) then
|
||||||
|
-- size information has just been read; we can now display it
|
||||||
|
formspec = formspec..build_chest.show_size_data( building_name );
|
||||||
|
|
||||||
|
-- do replacements for realtest where necessary (this needs to be done only once)
|
||||||
|
local replacements = {};
|
||||||
|
replacements_group['realtest'].replace( replacements );
|
||||||
|
meta:set_string( 'replacements', minetest.serialize( replacements ));
|
||||||
|
|
||||||
|
return formspec..build_chest.replacements_get_list_formspec( pos );
|
||||||
|
elseif( type(start_pos)=='string' ) then
|
||||||
|
return formspec.."label[3,3;Error reading building data:]"..
|
||||||
|
"label[3.5,3.5;"..start_pos.."]";
|
||||||
|
else
|
||||||
|
return formspec.."label[3,3;Error reading building data.]";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort( options );
|
||||||
|
|
||||||
|
local page_nr = meta:get_int( 'page_nr' );
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
|
||||||
|
-- found an end node of the menu graph
|
||||||
|
-- elseif( build_chest.stages_formspec_page_first_stage ) then
|
||||||
|
-- return build_chest.stages_formspec_page_first_stage( v.menu_path[( #current_path )], player, pos, meta, );
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- show the menu with the next options
|
||||||
|
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
|
||||||
|
|
||||||
|
return formspec;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.on_receive_fields = function(pos, formname, fields, player)
|
||||||
|
|
||||||
|
local meta = minetest.get_meta(pos);
|
||||||
|
|
||||||
|
local owner = meta:get_string('owner');
|
||||||
|
local pname = player:get_player_name();
|
||||||
|
|
||||||
|
-- make sure not everyone can mess up the build chest
|
||||||
|
if( owner and owner ~= '' and owner ~= pname
|
||||||
|
and minetest.is_protected( pos, pname )) then
|
||||||
|
minetest.chat_send_player( pname,
|
||||||
|
"Sorry. This build chest belongs to "..tostring( owner ).." and only "..
|
||||||
|
"accepts input from its owner or other players who can build here.");
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local building_name = meta:get_string('building_name' );
|
||||||
|
-- the statistic is needed for all the replacements later on as it also contains the list of nodenames
|
||||||
|
if( building_name and building_name~=""and not( build_chest.building[ building_name ].size )) then
|
||||||
|
build_chest.read_building( building_name );
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 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 );
|
||||||
|
meta:set_string( 'saved_as_filename', nil);
|
||||||
|
|
||||||
|
-- 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 ));
|
||||||
|
|
||||||
|
-- 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 );
|
||||||
|
|
||||||
|
-- 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 );
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
-- 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.replacements_apply( pos, meta, fields.replace_row_material, fields.replace_row_with );
|
||||||
|
|
||||||
|
elseif( fields.replace_rest_with_air ) then
|
||||||
|
build_chest.replacements_replace_rest_with_air( pos, meta );
|
||||||
|
|
||||||
|
elseif( fields.wood_selection ) then
|
||||||
|
build_chest.replacements_apply_for_group( pos, meta, 'wood', fields.wood_selection, fields.set_wood );
|
||||||
|
fields.set_wood = nil;
|
||||||
|
|
||||||
|
elseif( fields.farming_selection ) then
|
||||||
|
build_chest.replacements_apply_for_group( pos, meta, 'farming', fields.farming_selection, fields.set_farming );
|
||||||
|
fields.set_farming = nil;
|
||||||
|
|
||||||
|
elseif( fields.roof_selection ) then
|
||||||
|
build_chest.replacements_apply_for_group( pos, meta, 'roof', fields.roof_selection, fields.set_roof );
|
||||||
|
fields.set_roof = nil;
|
||||||
|
|
||||||
|
|
||||||
|
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'));
|
||||||
|
local filename = meta:get_string('backup' );
|
||||||
|
if( not( filename ) or filename == "" ) then
|
||||||
|
local base_filename = 'backup_'..
|
||||||
|
meta:get_string('owner')..'_'..
|
||||||
|
tostring( start_pos.x )..':'..tostring( start_pos.y )..':'..tostring( start_pos.z )..'_'..
|
||||||
|
'0_0';
|
||||||
|
|
||||||
|
-- store a backup of the original landscape
|
||||||
|
-- <worldname>/backup_PLAYERNAME_x_y_z_burried_rotation.mts
|
||||||
|
handle_schematics.create_schematic_with_meta( start_pos, end_pos, base_filename );
|
||||||
|
meta:set_string('backup', base_filename );
|
||||||
|
-- clear metadata so that the new building can be placed
|
||||||
|
handle_schematics.clear_meta( start_pos, end_pos );
|
||||||
|
|
||||||
|
minetest.chat_send_player( pname, 'CREATING backup schematic for this place in \"schems/'..base_filename..'.mts\".');
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: use scaffolding here (exchange some replacements)
|
||||||
|
local replacement_list = minetest.deserialize( meta:get_string( 'replacements' ));
|
||||||
|
local rotate = meta:get_string('rotate');
|
||||||
|
local mirror = meta:get_string('mirror');
|
||||||
|
local axis = build_chest.building[ building_name ].axis;
|
||||||
|
local no_plotmarker = 1;
|
||||||
|
-- actually place the building
|
||||||
|
--minetest.place_schematic( start_pos, building_name..'.mts', rotate, replacement_list, true );
|
||||||
|
mirror = nil;
|
||||||
|
fields.error_msg = handle_schematics.place_building_from_file( start_pos, end_pos, building_name, replacement_list, rotate, axis, mirror, no_plotmarker );
|
||||||
|
if( fields.error_msg ) then
|
||||||
|
fields.error_msg = 'Error: '..tostring( fields.error_msg );
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 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 and backup_file ~= "" ) then
|
||||||
|
if( save_restore.file_exists( 'schems/'..backup_file..'.mts' )) then
|
||||||
|
filename = minetest.get_worldpath()..'/schems/'..backup_file..'.mts';
|
||||||
|
minetest.place_schematic( start_pos, filename, "0", {}, true );
|
||||||
|
-- no rotation needed - the metadata can be applied as-is (with the offset applied)
|
||||||
|
handle_schematics.restore_meta( backup_file, nil, start_pos, end_pos, 0, nil);
|
||||||
|
meta:set_string('backup', nil );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- store a new end position
|
||||||
|
elseif( fields.set_end_pos ) then
|
||||||
|
local node = minetest.get_node( pos );
|
||||||
|
if( node and node.param2 ) then
|
||||||
|
build_chest.end_pos_list[ pname ] = {x=pos.x, y=pos.y, z=pos.z, param2=node.param2 };
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
elseif( fields.set_start_pos ) then
|
||||||
|
local error_msg = "";
|
||||||
|
local end_pos = build_chest.end_pos_list[ pname ];
|
||||||
|
if( not( end_pos )) then
|
||||||
|
error_msg = "Please mark the end position of your building first!";
|
||||||
|
else
|
||||||
|
local node = minetest.get_node( pos );
|
||||||
|
if( not( node ) or not( node.param2 )) then
|
||||||
|
error_msg = "A strange error happened.";
|
||||||
|
elseif( (node.param2 == 0 and end_pos.param2 ~= 2)
|
||||||
|
or (node.param2 == 1 and end_pos.param2 ~= 3)
|
||||||
|
or (node.param2 == 2 and end_pos.param2 ~= 0)
|
||||||
|
or (node.param2 == 3 and end_pos.param2 ~= 1)) then
|
||||||
|
error_msg = "One build chest needs to point to the front of your building, and "..
|
||||||
|
"the other one to the backside. This does not seem to be the case.";
|
||||||
|
|
||||||
|
elseif( (node.param2 == 2 and ( pos.x < end_pos.x or pos.z < end_pos.z )) -- x and z need to get larger
|
||||||
|
or (node.param2 == 3 and ( pos.x < end_pos.x or pos.z > end_pos.z )) -- x gets larger, z gets smaller
|
||||||
|
or (node.param2 == 0 and ( pos.x > end_pos.x or pos.z > end_pos.z )) -- x and z need to get smaller
|
||||||
|
or (node.param2 == 1 and ( pos.x > end_pos.x or pos.z < end_pos.z )) -- x gets smaller, z gets larger
|
||||||
|
) then
|
||||||
|
error_msg = "The end position does not fit to the orientation of this build chest.";
|
||||||
|
|
||||||
|
-- the chest takes up one node as well
|
||||||
|
elseif( math.abs(pos.x-end_pos.x)<1) then
|
||||||
|
error_msg = "Start- and end position share the same x value.";
|
||||||
|
|
||||||
|
elseif( math.abs(pos.z-end_pos.z)<1) then
|
||||||
|
error_msg = "Start- and end position share the same z value.";
|
||||||
|
|
||||||
|
-- all ok; we may proceed
|
||||||
|
else
|
||||||
|
error_msg = "";
|
||||||
|
build_chest.end_pos_list[ pname ].start_pos = {x=pos.x, y=pos.y, z=pos.z, param2=node.param2 };
|
||||||
|
end
|
||||||
|
fields.error_msg = error_msg;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- in case the player selected the wrong chest for the save dialog
|
||||||
|
elseif( fields.abort_set_start_pos ) then
|
||||||
|
local end_pos = build_chest.end_pos_list[ pname ];
|
||||||
|
if( end_pos ) then
|
||||||
|
build_chest.end_pos_list[ pname ].start_pos = nil;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
elseif( fields.save_as ) then
|
||||||
|
if( fields.save_as_p1 and fields.save_as_p2 and fields.save_as_filename ) then
|
||||||
|
-- restore p1 and p2, the positions of the area that is to be saved
|
||||||
|
local p1 = minetest.string_to_pos( fields.save_as_p1 );
|
||||||
|
local p2 = minetest.string_to_pos( fields.save_as_p2 );
|
||||||
|
|
||||||
|
-- take height changes into account
|
||||||
|
if( fields.save_as_height ) then
|
||||||
|
local new_height = tonumber( fields.save_as_height );
|
||||||
|
-- the new height is measured from the start position as well
|
||||||
|
if( new_height and new_height ~= (math.abs(p1.y-p2.y)+1)) then
|
||||||
|
p2.y = p1.y+new_height;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local burried = 0;
|
||||||
|
if( fields.save_as_yoff ) then
|
||||||
|
burried = tonumber( fields.save_as_yoff );
|
||||||
|
if( not( burried )) then
|
||||||
|
burried = 0;
|
||||||
|
end
|
||||||
|
-- the yoffset is applied to the start position
|
||||||
|
p1.y = p1.y + burried;
|
||||||
|
-- TODO: real negative values are not supported by analyze_mts_file
|
||||||
|
if( burried ~= 0 ) then
|
||||||
|
burried = -1*burried;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- create an automatic filename if none is provided
|
||||||
|
local filename = fields.save_as_filename;
|
||||||
|
-- TODO: check the input if it contains only allowed chars (a-z, A-Z, 0-9, -, _, .)
|
||||||
|
if( not( filename )) then
|
||||||
|
filename = pname..'_'..tostring( p1 )..'_'..tostring(p2);
|
||||||
|
end
|
||||||
|
|
||||||
|
-- param2 needs to be translated init initial rotation as well
|
||||||
|
local node = minetest.get_node( pos );
|
||||||
|
if( node.param2 == 0 ) then
|
||||||
|
filename = filename..'_'..burried..'_90';
|
||||||
|
elseif( node.param2 == 3 ) then
|
||||||
|
filename = filename..'_'..burried..'_180';
|
||||||
|
elseif( node.param2 == 1 ) then
|
||||||
|
filename = filename..'_'..burried..'_0';
|
||||||
|
elseif( node.param2 == 2 ) then
|
||||||
|
filename = filename..'_'..burried..'_270';
|
||||||
|
end
|
||||||
|
-- TODO: forbid overwriting existing files?
|
||||||
|
local worldpath = minetest.get_worldpath();
|
||||||
|
local filename_complete = worldpath..'/schems/'..filename..'.mts';
|
||||||
|
|
||||||
|
handle_schematics.create_schematic_with_meta( p1, p2, filename );
|
||||||
|
|
||||||
|
-- store that we have saved this area
|
||||||
|
meta:set_string('saved_as_filename', filename);
|
||||||
|
meta:set_string('p1', minetest.pos_to_string( p1 ));
|
||||||
|
meta:set_string('p2', minetest.pos_to_string( p2 ));
|
||||||
|
-- forget the end position
|
||||||
|
build_chest.end_pos_list[ pname ] = nil;
|
||||||
|
|
||||||
|
-- add this chest to the menu
|
||||||
|
local worldnameparts = string.split( worldpath, '/worlds/' );
|
||||||
|
if( not( worldnameparts ) or #worldnameparts < 1 ) then
|
||||||
|
worldnameparts = {'unkown world'};
|
||||||
|
end
|
||||||
|
build_chest.add_entry( {'main','worlds', worldnameparts[ #worldnameparts], 'schems', filename, worldpath..'/schems/'..filename});
|
||||||
|
build_chest.add_building( worldpath..'/schems/'..filename, {scm=filename, typ='nn'});
|
||||||
|
|
||||||
|
minetest.chat_send_player( pname,
|
||||||
|
'Created schematic \''..tostring( filename )..'\'. Saved area from '..
|
||||||
|
minetest.pos_to_string( p1 )..' to '..
|
||||||
|
minetest.pos_to_string( p2 ));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- the final build stage may offer further replacements
|
||||||
|
if( build_chest.stages_on_receive_fields ) then
|
||||||
|
build_chest.stages_on_receive_fields(pos, formname, fields, player, meta);
|
||||||
|
end
|
||||||
|
|
||||||
|
local formspec = build_chest.update_formspec( pos, 'main', player, fields );
|
||||||
|
-- add the position information so that we can show the formspec directly and still find out
|
||||||
|
-- which build chest was responsible
|
||||||
|
formspec = formspec.."field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]";
|
||||||
|
-- save the formspec data to the chest
|
||||||
|
meta:set_string( 'formspec', formspec );
|
||||||
|
-- show the formspec directly to the player to make it react more smoothly
|
||||||
|
minetest.show_formspec( pname, "handle_schematics:build", formspec );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_node("handle_schematics: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.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());
|
||||||
|
|
||||||
|
meta:set_string('formspec', 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.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.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
|
||||||
|
-- TODO: show this update directly to the player via minetest.show_formspec( pname, formname, formspec );
|
||||||
|
meta:set_string( 'formspec', 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,
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
-- a player clicked on something in a formspec he was shown
|
||||||
|
handle_schematics.form_input_handler = function( player, formname, fields)
|
||||||
|
if(formname == "handle_schematics:build" and fields and fields.pos2str) then
|
||||||
|
local pos = minetest.string_to_pos( fields.pos2str );
|
||||||
|
build_chest.on_receive_fields(pos, formname, fields, player);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make sure we receive player input; needed for showing formspecs directly (which is in turn faster than just updating the node)
|
||||||
|
minetest.register_on_player_receive_fields( handle_schematics.form_input_handler );
|
@ -0,0 +1,164 @@
|
|||||||
|
local build_chest_add_files_to_menu_from_directory = function( schem, path, entry_name, backup_name, menu_path_list)
|
||||||
|
-- we need the filename without extension (*.mts, *.we, *.wem)
|
||||||
|
local schemname = schem;
|
||||||
|
local i = string.find( schem, '.mts', -4 );
|
||||||
|
if( i ) then
|
||||||
|
schemname = string.sub( schem, 1, i-1 );
|
||||||
|
else
|
||||||
|
i = string.find( schem, '.we', -3 );
|
||||||
|
if( i ) then
|
||||||
|
schemname = string.sub( schem, 1, i-1 );
|
||||||
|
else
|
||||||
|
i = string.find( schem, '.wem', -4 );
|
||||||
|
if( i ) then
|
||||||
|
schemname = string.sub( schem, 1, i-1 );
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- only add known file types
|
||||||
|
if( not( schemname )) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
i = string.find( schemname, 'backup_' );
|
||||||
|
menu_path_list[ #menu_path_list+1 ] = schemname;
|
||||||
|
menu_path_list[ #menu_path_list+1 ] = path..schemname;
|
||||||
|
-- probably one of those automatic backups of the landscape
|
||||||
|
if( i and i==1 and backup_name) then
|
||||||
|
menu_path_list[1] = backup_name;
|
||||||
|
-- normal entry
|
||||||
|
else
|
||||||
|
menu_path_list[1] = entry_name;
|
||||||
|
end
|
||||||
|
build_chest.add_entry( menu_path_list);
|
||||||
|
build_chest.add_building( path..schemname, {scm=schemname, typ='nn'});
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- search for mods and modpacks containing schematics in any form
|
||||||
|
local build_chest_check_all_directories_mods_and_modpacks = function( path, menu_title, gamename )
|
||||||
|
local d2 = minetest.get_dir_list( path..'/mods', true );
|
||||||
|
for _,modname in ipairs( d2 ) do
|
||||||
|
local d3 = minetest.get_dir_list( path..'/mods/'..modname, true );
|
||||||
|
for _,subdir in ipairs( d3 ) do
|
||||||
|
if( subdir ~= 'textures' and subdir ~= 'sounds' and subdir ~= 'models' and subdir ~= '.git' and subdir ~= 'locale') then
|
||||||
|
local d4 = minetest.get_dir_list( path..'/mods/'..modname..'/'..subdir, false );
|
||||||
|
for _,filename in ipairs( d4 ) do
|
||||||
|
build_chest_add_files_to_menu_from_directory(
|
||||||
|
filename,
|
||||||
|
path..'/mods/'..modname..'/'..subdir..'/',
|
||||||
|
menu_title,
|
||||||
|
nil,
|
||||||
|
{'OVERWRITE THIS', gamename, modname} );
|
||||||
|
end
|
||||||
|
-- it might be a modpack
|
||||||
|
d4 = minetest.get_dir_list( path..'/mods/'..modname..'/'..subdir, true );
|
||||||
|
for _,subsubdir in ipairs( d4 ) do
|
||||||
|
if( subsubdir ~= 'textures' and subsubdir ~= 'sounds' and subsubdir ~= 'models' and subsubdir ~= '.git' and subsubdir ~= 'locale') then
|
||||||
|
local d5 = minetest.get_dir_list( path..'/mods/'..modname..'/'..subdir..'/'..subsubdir, false );
|
||||||
|
for _,filename in ipairs( d5 ) do
|
||||||
|
build_chest_add_files_to_menu_from_directory(
|
||||||
|
filename,
|
||||||
|
path..'/mods/'..modname..'/'..subdir..'/'..subsubdir..'/',
|
||||||
|
menu_title,
|
||||||
|
nil,
|
||||||
|
-- folders from modpacks get marked with a *..*
|
||||||
|
{'OVERWRITE THIS', gamename, '*'..subdir..'*'} );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local build_chest_check_all_directories = function()
|
||||||
|
-- find the name of the directory directly above the current worldpath
|
||||||
|
local worldpath = minetest.get_worldpath();
|
||||||
|
|
||||||
|
local p = 1;
|
||||||
|
local last_found = 1;
|
||||||
|
while( last_found ) do
|
||||||
|
p = last_found;
|
||||||
|
last_found = string.find( worldpath, '/', last_found+1 );
|
||||||
|
end
|
||||||
|
-- abort on Windows
|
||||||
|
if( p == 1 ) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
worldpath = string.sub( worldpath, 1, p );
|
||||||
|
|
||||||
|
--[[
|
||||||
|
local p = 1;
|
||||||
|
while( not( string.find( worldpath, '/', -1*p ))) do
|
||||||
|
p = p+1;
|
||||||
|
end
|
||||||
|
local found = 1;
|
||||||
|
for p=string.len( worldpath ),1,-1 do
|
||||||
|
if( p>found
|
||||||
|
and (string.byte( worldpath, p )=='/'
|
||||||
|
or string.byte( worldpath, p )=='\\')) then
|
||||||
|
found = p;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--]]
|
||||||
|
worldpath = string.sub( worldpath, 1, string.len( worldpath )-p );
|
||||||
|
|
||||||
|
|
||||||
|
-- locate .mts, .wem and .we files in the worlds/WORLDNAME/schems/* folders
|
||||||
|
local d1 = minetest.get_dir_list( worldpath, true );
|
||||||
|
for _,worldname in ipairs( d1 ) do
|
||||||
|
-- get list of subdirectories
|
||||||
|
local d2 = minetest.get_dir_list( worldpath..'/'..worldname, true );
|
||||||
|
for _,subdir in ipairs( d2 ) do
|
||||||
|
if( subdir=='schems' ) then
|
||||||
|
local d3 = minetest.get_dir_list( worldpath..'/'..worldname..'/schems', false );
|
||||||
|
for _,filename in ipairs( d3 ) do
|
||||||
|
build_chest_add_files_to_menu_from_directory(
|
||||||
|
filename,
|
||||||
|
worldpath..'/'..worldname..'/schems/',
|
||||||
|
'import from world',
|
||||||
|
'landscape backups',
|
||||||
|
{'OVERWRITE THIS', worldname });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local main_path = string.sub( worldpath, 1, string.len(worldpath)-string.len('/worlds'));
|
||||||
|
|
||||||
|
-- search in MODS/* subfolder
|
||||||
|
build_chest_check_all_directories_mods_and_modpacks( main_path, 'import from mod', 'mods' );
|
||||||
|
|
||||||
|
-- search in all GAMES/* folders for mods containing schematics
|
||||||
|
local game_path = main_path..'/games';
|
||||||
|
d1 = minetest.get_dir_list( game_path, true );
|
||||||
|
for _,gamename in ipairs( d1 ) do
|
||||||
|
build_chest_check_all_directories_mods_and_modpacks( game_path..'/'..gamename, 'import from game', gamename );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: hopfefully, security will get more relaxed regarding reading directories in the future
|
||||||
|
-- if security is enabled, our options to get schematics are a bit limited
|
||||||
|
if( minetest.setting_getbool( 'secure.enable_security' )) then
|
||||||
|
local worldpath = minetest.get_worldpath();
|
||||||
|
local d3 = minetest.get_dir_list( worldpath..'/schems', false );
|
||||||
|
if( d3 ) then
|
||||||
|
for _,filename in ipairs( d3 ) do
|
||||||
|
build_chest_add_files_to_menu_from_directory(
|
||||||
|
filename,
|
||||||
|
worldpath..'/schems/',
|
||||||
|
'import from world',
|
||||||
|
'landscape backups',
|
||||||
|
{'OVERWRITE THIS', '-current world-' });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- check worlds, mods and games folders for schematics and add them to the menu
|
||||||
|
build_chest_check_all_directories()
|
||||||
|
end
|
@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
|
||||||
|
build_chest.add_files_to_menu = function( path, add_path )
|
||||||
|
local file,err = io.open( path, "rb")
|
||||||
|
if (file == nil) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = file:read("*a");
|
||||||
|
file:close();
|
||||||
|
|
||||||
|
for schem_file_name in string.gmatch(text, "([^\r\n]*)[\r\n]*") do
|
||||||
|
if( schem_file_name and schem_file_name ~= "" ) then
|
||||||
|
local help = string.split( schem_file_name, '/', true, -1, false);
|
||||||
|
|
||||||
|
local i = #help;
|
||||||
|
local found = 1;
|
||||||
|
-- search from the end of the file name for the first occourance of "mods" or "worlds"
|
||||||
|
-- as that will be the path where we will put it into the menu
|
||||||
|
while (i>1 and found==1) do
|
||||||
|
if( help[i]=='mods' or help[i]=='worlds' ) then
|
||||||
|
found = i;
|
||||||
|
end
|
||||||
|
i = i-1;
|
||||||
|
end
|
||||||
|
|
||||||
|
local name = help[#help];
|
||||||
|
local length1 = string.len( name );
|
||||||
|
local length2 = string.len( schem_file_name );
|
||||||
|
-- remove the file name extension
|
||||||
|
if( string.sub( name, -4 )=='.mts' ) then
|
||||||
|
name = string.sub( name, 1, length1-4 );
|
||||||
|
schem_file_name = string.sub( schem_file_name, 1, length2-4 );
|
||||||
|
elseif( string.sub( name, -3 )=='.we' ) then
|
||||||
|
name = string.sub( name, 1, length1-3 );
|
||||||
|
schem_file_name = string.sub( schem_file_name, 1, length2-3 );
|
||||||
|
elseif( string.sub( name, -10 )==".schematic" ) then
|
||||||
|
name = string.sub( name, 1, length1-10);
|
||||||
|
schem_file_name = string.sub( schem_file_name, 1, length2-10);
|
||||||
|
end
|
||||||
|
help[#help] = name;
|
||||||
|
|
||||||
|
-- build the new menu path
|
||||||
|
local menu_path = {'main'};
|
||||||
|
for j=(i+1),#help do
|
||||||
|
table.insert( menu_path, help[j] );
|
||||||
|
end
|
||||||
|
schem_file_name = add_path..schem_file_name;
|
||||||
|
table.insert( menu_path, schem_file_name );
|
||||||
|
|
||||||
|
build_chest.add_entry( menu_path );
|
||||||
|
build_chest.add_building( schem_file_name, {scm=help[#help], typ='nn'});
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
build_chest.add_files_to_menu( minetest.get_modpath( minetest.get_current_modname()).."/list_of_schematics.txt", "");
|
@ -0,0 +1,256 @@
|
|||||||
|
-------------------------------------------------------------
|
||||||
|
--- contains the handling of replacements for the build chest
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
-- internal function
|
||||||
|
build_chest.replacements_get_extra_buttons = function( group, name, types_found_list, button_name, extra_buttons )
|
||||||
|
-- find out if there are any nodes that may need a group replacement
|
||||||
|
local found_type = "";
|
||||||
|
for k,w in ipairs( replacements_group[ group ].all ) do
|
||||||
|
-- we have found the full block of that group type
|
||||||
|
if( name == w ) then
|
||||||
|
found_type = w;
|
||||||
|
-- no primary node found; there may still be subordinate types
|
||||||
|
else
|
||||||
|
for nr,t in ipairs( replacements_group[ group ].data[ w ] ) do
|
||||||
|
if( name==t and not( types_found_list[ w ])) then
|
||||||
|
found_type = w;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if( found_type ~= "" and not( types_found_list[ found_type ])) then
|
||||||
|
extra_buttons.offset = extra_buttons.offset + 1;
|
||||||
|
extra_buttons.text = extra_buttons.text.."button[9.9,"..
|
||||||
|
tostring( (extra_buttons.offset*0.9)+2.8 )..";3.0,0.5;"..
|
||||||
|
tostring( button_name )..";"..
|
||||||
|
minetest.formspec_escape( found_type ).."]";
|
||||||
|
-- remember that we found and offered this type already; avoid duplicates
|
||||||
|
types_found_list[ found_type ] = 1;
|
||||||
|
end
|
||||||
|
return extra_buttons;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.replacements_get_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
|
||||||
|
if( not( build_chest.read_building( building_name ))) then
|
||||||
|
return "label[2,2;Error: Unable to read building file.]";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- used for setting wood type or plant(farming) type etc.
|
||||||
|
local extra_buttons = { text = "", offset = 0};
|
||||||
|
-- there may be wood types that only occour as stairs and/or slabs etc., without full blocks
|
||||||
|
local types_found_list_wood = {};
|
||||||
|
local types_found_list_farming = {};
|
||||||
|
local types_found_list_roof = {};
|
||||||
|
|
||||||
|
local not_the_first_entry = false;
|
||||||
|
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' and v[2] and v[2]>0) 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
|
||||||
|
|
||||||
|
-- avoid empty lines at the end
|
||||||
|
if( not_the_first_entry ) then
|
||||||
|
formspec = formspec..',';
|
||||||
|
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( j == replace_row ) then
|
||||||
|
replace_row_material = name;
|
||||||
|
if( repl ~= name ) then
|
||||||
|
replace_row_with = repl;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extra_buttons = build_chest.replacements_get_extra_buttons( 'wood', name, types_found_list_wood, 'set_wood', extra_buttons );
|
||||||
|
extra_buttons = build_chest.replacements_get_extra_buttons( 'farming', name, types_found_list_farming, 'set_farming', extra_buttons );
|
||||||
|
extra_buttons = build_chest.replacements_get_extra_buttons( 'roof', name, types_found_list_farming, 'set_roof', extra_buttons );
|
||||||
|
|
||||||
|
j=j+1;
|
||||||
|
|
||||||
|
not_the_first_entry = true;
|
||||||
|
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]";
|
||||||
|
else
|
||||||
|
formspec = formspec.."button[9.9,9.0;3.2,0.5;replace_rest_with_air;Suggest air for unknown]";
|
||||||
|
end
|
||||||
|
formspec = formspec.."button[9.9,1.0;2.0,0.5;preview;Preview]";
|
||||||
|
if( extra_buttons.text and extra_buttons.text ~= "" ) then
|
||||||
|
formspec = formspec..extra_buttons.text..
|
||||||
|
"label[9.9,2.8;Replace by type:]";
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
-- set replacements for all unknown nodes to air so that the building can be spawned
|
||||||
|
build_chest.replacements_replace_rest_with_air = function( pos, meta )
|
||||||
|
local building_name = meta:get_string( 'building_name' );
|
||||||
|
if( not( building_name ) or not( build_chest.building[ building_name ])) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
local replacements_orig = minetest.deserialize( meta:get_string( 'replacements' ));
|
||||||
|
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' and v[2] and v[2]>0) then
|
||||||
|
-- find out if this node name gets replaced
|
||||||
|
local repl = name;
|
||||||
|
for j,r in ipairs( replacements_orig ) do
|
||||||
|
if( r and r[1]==name ) then
|
||||||
|
repl = r[2];
|
||||||
|
-- set replacements for inexisting nodes to air
|
||||||
|
if( not( minetest.registered_nodes[ repl ] )) then
|
||||||
|
r[2] = 'air';
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- replace nodes that do not exist with air
|
||||||
|
if( not( repl ) or not( minetest.registered_nodes[ repl ])) then
|
||||||
|
table.insert( replacements_orig, { name, 'air' });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- store the new set of replacements
|
||||||
|
meta:set_string( 'replacements', minetest.serialize( replacements_orig ));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.replacements_apply = 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
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.replacements_get_group_list_formspec = function( pos, group, button_name )
|
||||||
|
local formspec = "";
|
||||||
|
for i,v in ipairs( replacements_group[ group ].found ) do
|
||||||
|
formspec = formspec.."item_image_button["..tostring(((i-1)%8)+1)..","..
|
||||||
|
tostring(3+math.floor((i-1)/8))..";1,1;"..
|
||||||
|
tostring( v )..";"..tostring( button_name )..";"..tostring(i).."]";
|
||||||
|
end
|
||||||
|
return formspec;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
build_chest.replacements_apply_for_group = function( pos, meta, group, selected, old_material )
|
||||||
|
local nr = tonumber( selected );
|
||||||
|
if( not(nr) or nr <= 0 or nr > #replacements_group[ group ].found ) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local new_material = replacements_group[ group ].found[ nr ];
|
||||||
|
if( old_material and old_material == new_material ) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local replacements = minetest.deserialize( meta:get_string( 'replacements' ));
|
||||||
|
if( not( replacements )) then
|
||||||
|
replacements = {};
|
||||||
|
end
|
||||||
|
replacements_group[ group ].replace_material( replacements, old_material, new_material );
|
||||||
|
|
||||||
|
-- store the new set of replacements
|
||||||
|
meta:set_string( 'replacements', minetest.serialize( replacements ));
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,248 @@
|
|||||||
|
|
||||||
|
build_chest.preview_image_draw_tile = function( content_id, image, x, z, dx, dz, tile_nr )
|
||||||
|
if( not( image )) then
|
||||||
|
local node_name = minetest.get_name_from_content_id( content_id );
|
||||||
|
if( not( node_name )) then
|
||||||
|
return '';
|
||||||
|
end
|
||||||
|
local node_def = minetest.registered_nodes[ node_name ];
|
||||||
|
if( not( node_def )) then
|
||||||
|
return '';
|
||||||
|
end
|
||||||
|
local tiles = node_def.tiles;
|
||||||
|
if( not( tiles )) then
|
||||||
|
tiles = node_def.tile_images;
|
||||||
|
end
|
||||||
|
local tile = nil;
|
||||||
|
if( tiles ~= nil ) then
|
||||||
|
if( not(tile_nr) or tile_nr > #tiles or tile_nr < 1 ) then
|
||||||
|
tile_nr = 1;
|
||||||
|
end
|
||||||
|
tile = tiles[tile_nr];
|
||||||
|
end
|
||||||
|
if type(tile)=="table" then
|
||||||
|
tile=tile["name"]
|
||||||
|
end
|
||||||
|
image = tile;
|
||||||
|
if( not( image )) then
|
||||||
|
image = "unknown_object.png";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return "image["..tostring(x)..",".. tostring(z) ..";"..dx..','..dz..";" .. image .."]";
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- creates a 2d preview image (or rather, the data structure for it) of the building
|
||||||
|
-- internal function
|
||||||
|
build_chest.preview_image_create_one_view = function( data, side )
|
||||||
|
local params = {1, data.size.x, 1, 1, data.size.z, 1, 0, 0};
|
||||||
|
if( side==1 ) then
|
||||||
|
params = {1, data.size.x, 1, 1, data.size.z, 1, 0, 0};
|
||||||
|
elseif( side==2 ) then
|
||||||
|
params = {1, data.size.z, 1, 1, data.size.x, 1, 1, 1};
|
||||||
|
elseif( side==3 ) then
|
||||||
|
params = {1, data.size.x, 1, data.size.z, 0, -1, 0, 1};
|
||||||
|
elseif( side==4 ) then
|
||||||
|
params = {1, data.size.z, 1, data.size.x, 0, -1, 1, 0};
|
||||||
|
end
|
||||||
|
|
||||||
|
-- do not create preview images for buildings that are too big
|
||||||
|
if( params[2] * params[4] > 2500 ) then
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
local preview = {};
|
||||||
|
for y = 1, data.size.y do
|
||||||
|
preview[ y ] = {};
|
||||||
|
for x = params[1], params[2], params[3] do
|
||||||
|
local found = nil;
|
||||||
|
local z = params[4];
|
||||||
|
local target_x = x;
|
||||||
|
if( params[8]==1 ) then
|
||||||
|
target_x = math.max( params[1],params[2] )- x;
|
||||||
|
end
|
||||||
|
while( not( found ) and z~= params[5]) do
|
||||||
|
local node = -1;
|
||||||
|
if( params[7]==0 ) then
|
||||||
|
node = data.scm_data_cache[y][x][z];
|
||||||
|
else
|
||||||
|
node = data.scm_data_cache[y][z][x];
|
||||||
|
end
|
||||||
|
if( node and node[1]
|
||||||
|
and data.nodenames[ node[1] ]
|
||||||
|
and data.nodenames[ node[1] ] ~= 'air'
|
||||||
|
and data.nodenames[ node[1] ] ~= 'ignore'
|
||||||
|
and data.nodenames[ node[1] ] ~= 'mg:ignore'
|
||||||
|
and data.nodenames[ node[1] ] ~= 'default:torch' ) then
|
||||||
|
-- a preview node is only set if there's no air there
|
||||||
|
preview[y][target_x] = node[1];
|
||||||
|
found = 1;
|
||||||
|
end
|
||||||
|
z = z+params[6];
|
||||||
|
end
|
||||||
|
if( not( found )) then
|
||||||
|
preview[y][target_x] = -1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return preview;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- internal function
|
||||||
|
build_chest.preview_image_create_view_from_top = function( data )
|
||||||
|
-- no view from top if the image is too big
|
||||||
|
if( data.size.z * data.size.y > 2500 ) then
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
|
||||||
|
local preview = {};
|
||||||
|
for z = 1, data.size.z do
|
||||||
|
preview[ z ] = {};
|
||||||
|
for x = 1, data.size.x do
|
||||||
|
local found = nil;
|
||||||
|
local y = data.size.y;
|
||||||
|
while( not( found ) and y > 1) do
|
||||||
|
local node = data.scm_data_cache[y][x][z];
|
||||||
|
if( node and node[1]
|
||||||
|
and data.nodenames[ node[1] ]
|
||||||
|
and data.nodenames[ node[1] ] ~= 'air'
|
||||||
|
and data.nodenames[ node[1] ] ~= 'ignore'
|
||||||
|
and data.nodenames[ node[1] ] ~= 'mg:ignore'
|
||||||
|
and data.nodenames[ node[1] ] ~= 'default:torch' ) then
|
||||||
|
-- a preview node is only set if there's no air there
|
||||||
|
preview[z][x] = node[1];
|
||||||
|
found = 1;
|
||||||
|
end
|
||||||
|
y = y-1;
|
||||||
|
end
|
||||||
|
if( not( found )) then
|
||||||
|
preview[z][x] = -1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return preview;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- function called by the build chest to display one view
|
||||||
|
build_chest.preview_image_formspec = function( building_name, replacements, side_name )
|
||||||
|
if( not( building_name )
|
||||||
|
or not( build_chest.building[ building_name ] )
|
||||||
|
or not( build_chest.building[ building_name ].preview )) then
|
||||||
|
return "";
|
||||||
|
end
|
||||||
|
|
||||||
|
local side_names = {"front","right","back","left","top"};
|
||||||
|
local side = 1;
|
||||||
|
for i,v in ipairs( side_names ) do
|
||||||
|
if( side_name and side_name==v ) then
|
||||||
|
side = i;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local formspec = "";
|
||||||
|
for i=1,5 do
|
||||||
|
if( i ~= side ) then
|
||||||
|
formspec = formspec.."button["..tostring(3.3+1.2*(i-1))..
|
||||||
|
",2.2;1,0.5;preview;"..side_names[i].."]";
|
||||||
|
else
|
||||||
|
formspec = formspec.."label["..tostring(3.3+1.2*(i-1))..",2.2;"..side_names[i].."]";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = build_chest.building[ building_name ];
|
||||||
|
|
||||||
|
-- the draw_tile function is based on content_id
|
||||||
|
local content_ids = {};
|
||||||
|
for i,v in ipairs( data.nodenames ) do
|
||||||
|
local found = false;
|
||||||
|
for j,w in ipairs( replacements ) do
|
||||||
|
if( w and w[1] and w[1]==v) then
|
||||||
|
found = true;
|
||||||
|
if( minetest.registered_nodes[ w[2]] ) then
|
||||||
|
content_ids[ i ] = minetest.get_content_id( w[2] );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if( not( found )) then
|
||||||
|
if( minetest.registered_nodes[ v ]) then
|
||||||
|
content_ids[ i ] = minetest.get_content_id( v );
|
||||||
|
elseif( v ~= 'air' ) then
|
||||||
|
content_ids[ i ] = -1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local scale = 0.5;
|
||||||
|
|
||||||
|
local tile_nr = 3; -- view from the side
|
||||||
|
if( side ~= 5 ) then
|
||||||
|
local scale_y = 6.0/data.size.y;
|
||||||
|
local scale_z = 10.0/data.size.z;
|
||||||
|
if( scale_y > scale_z) then
|
||||||
|
scale = scale_z;
|
||||||
|
else
|
||||||
|
scale = scale_y;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local scale_x = 10.0/data.size.x; -- only relevant for view from top
|
||||||
|
local scale_z = 6.0/data.size.z;
|
||||||
|
if( scale_x > scale_z) then
|
||||||
|
scale = scale_z;
|
||||||
|
else
|
||||||
|
scale = scale_x;
|
||||||
|
end
|
||||||
|
tile_nr = 1; -- view from top
|
||||||
|
end
|
||||||
|
|
||||||
|
if( not( side )) then
|
||||||
|
side = 1;
|
||||||
|
end
|
||||||
|
local preview = data.preview[ side ];
|
||||||
|
if( not( preview )) then
|
||||||
|
formspec = formspec.."label[3,3;Sorry, this schematic is too big for a preview image.]";
|
||||||
|
return formspec;
|
||||||
|
end
|
||||||
|
for y,y_values in ipairs( preview ) do
|
||||||
|
for l,v in ipairs( y_values ) do
|
||||||
|
-- air, ignore and mg:ignore are not stored
|
||||||
|
if( v and content_ids[ v ]==-1 ) then
|
||||||
|
formspec = formspec..build_chest.preview_image_draw_tile( nil, "unknown_node.png", (l*scale), 9-(y*scale), scale*1.3, scale*1.2, tile_nr);
|
||||||
|
elseif( v and v>0 and content_ids[v]) then
|
||||||
|
formspec = formspec..build_chest.preview_image_draw_tile( content_ids[ v ], nil, (l*scale), 9-(y*scale), scale*1.3, scale*1.2, tile_nr);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return formspec;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- create all five preview images
|
||||||
|
build_chest.preview_image_create_views = function( res, orients )
|
||||||
|
|
||||||
|
-- create a 2d overview image (or rather, the data structure for it)
|
||||||
|
local preview = {
|
||||||
|
build_chest.preview_image_create_one_view( res, 2 ),
|
||||||
|
build_chest.preview_image_create_one_view( res, 1 ),
|
||||||
|
build_chest.preview_image_create_one_view( res, 4 ),
|
||||||
|
build_chest.preview_image_create_one_view( res, 3 )};
|
||||||
|
|
||||||
|
-- the building might be stored in rotated form
|
||||||
|
if( orients and #orients and orients[1] ) then
|
||||||
|
if( orients[1]==1 ) then
|
||||||
|
preview = {preview[2],preview[3],preview[4],preview[1]};
|
||||||
|
elseif( orients[1]==2 ) then
|
||||||
|
preview = {preview[3],preview[4],preview[1],preview[2]};
|
||||||
|
elseif( orients[1]==3 ) then
|
||||||
|
preview = {preview[4],preview[1],preview[2],preview[3]};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- ...and add a preview image from top
|
||||||
|
preview[5] = build_chest.preview_image_create_view_from_top( res );
|
||||||
|
return preview;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- this function makes sure that the building will always extend to the right and in front of the build chest
|
23
mods/a_mapgen_mods/handle_schematics/depends.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
default?
|
||||||
|
doors?
|
||||||
|
farming?
|
||||||
|
wool?
|
||||||
|
stairs?
|
||||||
|
cottages?
|
||||||
|
moretrees?
|
||||||
|
trees?
|
||||||
|
forest?
|
||||||
|
dryplants?
|
||||||
|
cavestuff?
|
||||||
|
snow?
|
||||||
|
moresnow?
|
||||||
|
darkage?
|
||||||
|
ethereal?
|
||||||
|
deco?
|
||||||
|
metals?
|
||||||
|
grounds?
|
||||||
|
moreblocks?
|
||||||
|
bell?
|
||||||
|
mobf_trader?
|
||||||
|
docfarming?
|
||||||
|
mccompat?
|
162
mods/a_mapgen_mods/handle_schematics/handle_schematics_meta.lua
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
|
||||||
|
|
||||||
|
handle_schematics.sort_pos_get_size = function( p1, p2 )
|
||||||
|
local res = {x=p1.x, y=p1.y, z=p1.z,
|
||||||
|
sizex = math.abs( p1.x - p2.x )+1,
|
||||||
|
sizey = math.abs( p1.y - p2.y )+1,
|
||||||
|
sizez = math.abs( p1.z - p2.z )+1};
|
||||||
|
if( p2.x < p1.x ) then
|
||||||
|
res.x = p2.x;
|
||||||
|
end
|
||||||
|
if( p2.y < p1.y ) then
|
||||||
|
res.y = p2.y;
|
||||||
|
end
|
||||||
|
if( p2.z < p1.z ) then
|
||||||
|
res.z = p2.z;
|
||||||
|
end
|
||||||
|
return res;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local handle_schematics_get_meta_table = function( pos, all_meta, start_pos )
|
||||||
|
local m = minetest.get_meta( pos ):to_table();
|
||||||
|
local empty_meta = true;
|
||||||
|
|
||||||
|
-- the inventory part contains functions and cannot be fed to minetest.serialize directly
|
||||||
|
local invlist = {};
|
||||||
|
local count_inv = 0;
|
||||||
|
local inv_is_empty = true;
|
||||||
|
for name, list in pairs( m.inventory ) do
|
||||||
|
invlist[ name ] = {};
|
||||||
|
count_inv = count_inv + 1;
|
||||||
|
for i, stack in ipairs(list) do
|
||||||
|
if( not( stack:is_empty())) then
|
||||||
|
invlist[ name ][ i ] = stack:to_string();
|
||||||
|
empty_meta = false;
|
||||||
|
inv_is_empty = false;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- the fields part at least is unproblematic
|
||||||
|
local count_fields = 0;
|
||||||
|
if( empty_meta and m.fields ) then
|
||||||
|
for k,v in pairs( m.fields ) do
|
||||||
|
empty_meta = false;
|
||||||
|
count_fields = count_fields + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ignore default:sign_wall without text on it
|
||||||
|
if( count_inv==0
|
||||||
|
and count_fields<=3 and m.fields.formspec and m.fields.infotext
|
||||||
|
and m.fields.formspec == "field[text;;${text}]"
|
||||||
|
and m.fields.infotext == "\"\"") then
|
||||||
|
-- also consider signs empty if their text has been set once and deleted afterwards
|
||||||
|
if( not( m.fields.text ) or m.fields.text == "" ) then
|
||||||
|
print('SKIPPING empty sign AT '..minetest.pos_to_string( pos)..' while saving metadata.');
|
||||||
|
empty_meta = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( count_inv > 0 and inv_is_empty
|
||||||
|
and count_fields>0 and m.fields.formspec ) then
|
||||||
|
|
||||||
|
local n = minetest.get_node( pos );
|
||||||
|
if( n and n.name
|
||||||
|
and (n.name=='default:chest' or n.name=='default:chest_locked' or n.name=='default:bookshelf'
|
||||||
|
or n.name=='default:furnace' or n.name=='default:furnace_active'
|
||||||
|
or n.name=='cottages:shelf' or n.name=='cottages:anvil' or n.name=='cottages:threshing_floor' )) then
|
||||||
|
print('SKIPPING empty '..tostring(n.name)..' AT '..minetest.pos_to_string( pos )..' while saving metadata.');
|
||||||
|
empty_meta = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- only save if there is something to be saved
|
||||||
|
if( not( empty_meta )) then
|
||||||
|
-- positions are stored as relative positions
|
||||||
|
all_meta[ #all_meta+1 ] = {
|
||||||
|
x=pos.x-start_pos.x,
|
||||||
|
y=pos.y-start_pos.y,
|
||||||
|
z=pos.z-start_pos.z,
|
||||||
|
fields = m.fields,
|
||||||
|
inventory = invlist};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- reads metadata values from start_pos to end_pos and stores them in a file
|
||||||
|
handle_schematics.save_meta = function( start_pos, end_pos, filename )
|
||||||
|
local all_meta = {};
|
||||||
|
local p = handle_schematics.sort_pos_get_size( start_pos, end_pos );
|
||||||
|
|
||||||
|
if( minetest.find_nodes_with_meta ) then
|
||||||
|
for _,pos in ipairs( minetest.find_nodes_with_meta( start_pos, end_pos )) do
|
||||||
|
handle_schematics_get_meta_table( pos, all_meta, p );
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for x=p.x, p.x+p.sizex do
|
||||||
|
for y=p.y, p.y+p.sizey do
|
||||||
|
for z=p.z, p.z+p.sizez do
|
||||||
|
handle_schematics_get_meta_table( {x=x-p.x, y=y-p.y, z=z-p.z}, all_meta, p );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if( #all_meta > 0 ) then
|
||||||
|
save_restore.save_data( 'schems/'..filename..'.meta', all_meta );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- all metadata values will be deleted when this function is called,
|
||||||
|
-- making the area ready for new voxelmanip/schematic data
|
||||||
|
handle_schematics.clear_meta = function( start_pos, end_pos )
|
||||||
|
local empty_meta = { inventory = {}, fields = {} };
|
||||||
|
|
||||||
|
if( minetest.find_nodes_with_meta ) then
|
||||||
|
for _,pos in ipairs( minetest.find_nodes_with_meta( start_pos, end_pos )) do
|
||||||
|
local meta = minetest.get_meta( pos );
|
||||||
|
meta:from_table( empty_meta );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- restore metadata from file
|
||||||
|
-- TODO: use relative instead of absolute positions (already done for .we files)
|
||||||
|
-- TODO: handle mirror
|
||||||
|
handle_schematics.restore_meta = function( filename, all_meta, start_pos, end_pos, rotate, mirror )
|
||||||
|
|
||||||
|
if( not( all_meta ) and filename ) then
|
||||||
|
all_meta = save_restore.restore_data( 'schems/'..filename..'.meta' );
|
||||||
|
end
|
||||||
|
for _,pos in ipairs( all_meta ) do
|
||||||
|
local p = {};
|
||||||
|
if( rotate == 0 ) then
|
||||||
|
p = {x=start_pos.x+pos.x-1, y=start_pos.y+pos.y-1, z=start_pos.z+pos.z-1};
|
||||||
|
elseif( rotate == 1 ) then
|
||||||
|
p = {x=start_pos.x+pos.z-1, y=start_pos.y+pos.y-1, z=end_pos.z -pos.x+1};
|
||||||
|
elseif( rotate == 2 ) then
|
||||||
|
p = {x=end_pos.x -pos.x+1, y=start_pos.y+pos.y-1, z=end_pos.z -pos.z+1};
|
||||||
|
elseif( rotate == 3 ) then
|
||||||
|
p = {x=end_pos.x -pos.z+1, y=start_pos.y+pos.y-1, z=start_pos.z+pos.x-1};
|
||||||
|
end
|
||||||
|
local meta = minetest.get_meta( p );
|
||||||
|
meta:from_table( {inventory = pos.inventory, fields = pos.fields });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- return true on success; will overwrite existing files
|
||||||
|
handle_schematics.create_schematic_with_meta = function( p1, p2, base_filename )
|
||||||
|
|
||||||
|
-- create directory for the schematics (same path as WorldEdit uses)
|
||||||
|
save_restore.create_directory( '/schems' );
|
||||||
|
local complete_filename = minetest.get_worldpath()..'/schems/'..base_filename..'.mts';
|
||||||
|
-- actually create the schematic
|
||||||
|
minetest.create_schematic( p1, p2, nil, complete_filename, nil);
|
||||||
|
-- save metadata; the file will only be created if there is any metadata that is to be saved
|
||||||
|
handle_schematics.save_meta( p1, p2, base_filename );
|
||||||
|
|
||||||
|
return save_restore.file_exists( complete_filename );
|
||||||
|
end
|
107
mods/a_mapgen_mods/handle_schematics/handle_schematics_misc.lua
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
-- helper function; sorts by the second element of the table
|
||||||
|
local function handle_schematics_comp(a,b)
|
||||||
|
if (a[2] > b[2]) then
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- create a statistic about how frequent each node name occoured
|
||||||
|
handle_schematics.count_nodes = function( data )
|
||||||
|
local statistic = {};
|
||||||
|
-- make sure all node names are counted (air may sometimes be included without occouring)
|
||||||
|
for id=1, #data.nodenames do
|
||||||
|
statistic[ id ] = { id, 0};
|
||||||
|
end
|
||||||
|
|
||||||
|
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];
|
||||||
|
if( a ) then
|
||||||
|
local id = 0;
|
||||||
|
if( type( a )=='table' ) then
|
||||||
|
id = a[1];
|
||||||
|
else
|
||||||
|
id = a;
|
||||||
|
end
|
||||||
|
if( statistic[ id ] and statistic[ id ][ 2 ] ) then
|
||||||
|
statistic[ id ] = { id, statistic[ id ][ 2 ]+1 };
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort( statistic, handle_schematics_comp );
|
||||||
|
return statistic;
|
||||||
|
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, yoff )
|
||||||
|
|
||||||
|
-- mg_villages stores available rotations of buildings in orients={0,1,2,3] format
|
||||||
|
if( orients and #orients and orients[1]~=0) then
|
||||||
|
-- reset rotated - else we'd apply it twice
|
||||||
|
rotated = 0;
|
||||||
|
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 and burried ~= 0 and yoff == nil ) 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
|
||||||
|
|
61
mods/a_mapgen_mods/handle_schematics/init.lua
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
handle_schematics = {}
|
||||||
|
|
||||||
|
handle_schematics.modpath = minetest.get_modpath( "handle_schematics");
|
||||||
|
|
||||||
|
-- adds worldedit_file.* namespace
|
||||||
|
-- deserialize worldedit savefiles
|
||||||
|
dofile(handle_schematics.modpath.."/worldedit_file.lua")
|
||||||
|
|
||||||
|
-- uses handle_schematics.* namespace
|
||||||
|
-- reads and analyzes .mts files (minetest schematics)
|
||||||
|
dofile(handle_schematics.modpath.."/analyze_mts_file.lua")
|
||||||
|
-- reads and analyzes worldedit files
|
||||||
|
dofile(handle_schematics.modpath.."/analyze_we_file.lua")
|
||||||
|
-- reads and analyzes Minecraft schematic files
|
||||||
|
dofile(handle_schematics.modpath.."/translate_nodenames_for_mc_schematic.lua")
|
||||||
|
dofile(handle_schematics.modpath.."/analyze_mc_schematic_file.lua")
|
||||||
|
-- handles rotation and mirroring
|
||||||
|
dofile(handle_schematics.modpath.."/rotate.lua")
|
||||||
|
-- count nodes, take param2 into account for rotation etc.
|
||||||
|
dofile(handle_schematics.modpath.."/handle_schematics_misc.lua")
|
||||||
|
|
||||||
|
-- store and restore metadata
|
||||||
|
dofile(handle_schematics.modpath.."/save_restore.lua");
|
||||||
|
dofile(handle_schematics.modpath.."/handle_schematics_meta.lua");
|
||||||
|
|
||||||
|
-- uses replacements_group.* namespace
|
||||||
|
-- these functions are responsible for the optional dependencies; they check
|
||||||
|
-- which nodes are available and may be offered as possible replacements
|
||||||
|
replacements_group = {};
|
||||||
|
-- the replacement groups do add some non-ground nodes; needed by mg_villages
|
||||||
|
replacements_group.node_is_ground = {}
|
||||||
|
dofile(handle_schematics.modpath.."/replacements_wood.lua")
|
||||||
|
dofile(handle_schematics.modpath.."/replacements_realtest.lua")
|
||||||
|
dofile(handle_schematics.modpath.."/replacements_farming.lua")
|
||||||
|
dofile(handle_schematics.modpath.."/replacements_roof.lua")
|
||||||
|
|
||||||
|
-- transforms the replacement list into a table;
|
||||||
|
-- also creates a replacement if needed and replaces default:torch
|
||||||
|
dofile(handle_schematics.modpath.."/replacements_get_table.lua")
|
||||||
|
|
||||||
|
-- uses build_chest.* namespace
|
||||||
|
-- a chest for spawning buildings manually
|
||||||
|
dofile(handle_schematics.modpath.."/build_chest.lua")
|
||||||
|
-- makes the replacements from replacements_group.* available to the build chest
|
||||||
|
dofile(handle_schematics.modpath.."/build_chest_handle_replacements.lua");
|
||||||
|
-- creates 2d previews of the schematic from left/right/back/front/top
|
||||||
|
dofile(handle_schematics.modpath.."/build_chest_preview_image.lua");
|
||||||
|
-- reads a file and adds the files listed there as menu entries
|
||||||
|
dofile(handle_schematics.modpath.."/build_chest_add_schems_from_file.lua");
|
||||||
|
-- locate schematics through directories
|
||||||
|
dofile(handle_schematics.modpath.."/build_chest_add_schems_by_directory.lua");
|
||||||
|
|
||||||
|
-- the main functionality of the mod;
|
||||||
|
-- provides the function handle_schematics.place_building_from_file
|
||||||
|
-- (and also place_buildings for mg_villages)
|
||||||
|
dofile(handle_schematics.modpath.."/place_buildings.lua")
|
||||||
|
|
||||||
|
-- dofile(handle_schematics.modpath.."/fill_chest.lua")
|
||||||
|
|
||||||
|
dofile(handle_schematics.modpath.."/nodes.lua")
|
24
mods/a_mapgen_mods/handle_schematics/nodes.lua
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
-- helper node that is used during construction of a house; scaffolding
|
||||||
|
---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
minetest.register_node("handle_schematics:support", {
|
||||||
|
description = "support structure for buildings",
|
||||||
|
tiles = {"handle_schematics_support.png"},
|
||||||
|
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
|
||||||
|
walkable = false,
|
||||||
|
climbable = true,
|
||||||
|
paramtype = "light",
|
||||||
|
drawtype = "plantlike",
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "handle_schematics:support",
|
||||||
|
recipe = {
|
||||||
|
{"default:stick", "", "default:stick", }
|
||||||
|
}
|
||||||
|
})
|
835
mods/a_mapgen_mods/handle_schematics/place_buildings.lua
Normal file
@ -0,0 +1,835 @@
|
|||||||
|
-- TODO: this function also occours in replacements.lua
|
||||||
|
handle_schematics.get_content_id_replaced = function( node_name, replacements )
|
||||||
|
if( not( node_name ) or not( replacements ) or not(replacements.table )) then
|
||||||
|
return minetest.get_content_id( 'ignore' );
|
||||||
|
end
|
||||||
|
if( replacements.table[ node_name ]) then
|
||||||
|
return minetest.get_content_id( replacements.table[ node_name ] );
|
||||||
|
else
|
||||||
|
return minetest.get_content_id( node_name );
|
||||||
|
end
|
||||||
|
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
|
||||||
|
handle_schematics.mg_drop_moresnow = function( x, z, y_top, y_bottom, a, data, param2_data)
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
if( node_below.content == minetest.get_content_id("default:water_source")
|
||||||
|
or node_below.content == minetest.get_content_id("default:river_water_source")) then
|
||||||
|
return { height = y, suggested = {new_id = minetest.get_content_id('default:ice'), param2 = 0 }};
|
||||||
|
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
|
||||||
|
get_drop = minetest.registered_nodes[ get_drop ];
|
||||||
|
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};
|
||||||
|
if( pos.o == 0 ) then
|
||||||
|
p.x = p.x - 1;
|
||||||
|
p.z = p.z + pos.bsizez - 1;
|
||||||
|
elseif( pos.o == 2 ) then
|
||||||
|
p.x = p.x + pos.bsizex;
|
||||||
|
elseif( pos.o == 1 ) then
|
||||||
|
p.z = p.z + pos.bsizez;
|
||||||
|
p.x = p.x + pos.bsizex - 1;
|
||||||
|
elseif( pos.o == 3 ) then
|
||||||
|
p.z = p.z - 1;
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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 ));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
-- 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;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- only existing nodes can be placed
|
||||||
|
if( new_node_name and minetest.registered_nodes[ new_node_name ]) then
|
||||||
|
|
||||||
|
local regnode = minetest.registered_nodes[ new_node_name ];
|
||||||
|
|
||||||
|
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;
|
||||||
|
if( new_content == cid.c_dirt or new_content == cid.c_dirt_with_grass ) then
|
||||||
|
new_nodes[ i ].is_grass = 1;
|
||||||
|
|
||||||
|
elseif( new_content == cid.c_sapling
|
||||||
|
or new_content == cid.c_jsapling
|
||||||
|
or new_content == cid.c_psapling
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
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
|
||||||
|
if( node_name == 'default:ladder' and not( minetest.registered_nodes[ node_name ])) then
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
local function generate_building(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, building_nr_in_bpos, village_id, binfo_extra, road_node, keep_ground)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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" );
|
||||||
|
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
local t = scm[y+1][xoff][zoff];
|
||||||
|
|
||||||
|
local node_content = data[a:index(ax, ay, az)];
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
data[ a:index(ax, ay, az)] = cid.c_air;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
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) then
|
||||||
|
new_content = ground_type;
|
||||||
|
end
|
||||||
|
|
||||||
|
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}};
|
||||||
|
else
|
||||||
|
table.insert( extra_calls.on_constr[ new_content ], {x=ax, y=ay, z=az});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- do not overwrite plotmarkers
|
||||||
|
if( new_content ~= cid.c_air or node_content ~= cid.c_plotmarker ) then
|
||||||
|
data[ a:index(ax, ay, az)] = new_content;
|
||||||
|
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});
|
||||||
|
|
||||||
|
-- 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});
|
||||||
|
|
||||||
|
-- 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});
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle rotation
|
||||||
|
if( n.paramtype2 ) then
|
||||||
|
local param2 = t[2];
|
||||||
|
if( n.change_param2 and n.change_param2[ t[2] ]) then
|
||||||
|
param2 = n.change_param2[ param2 ];
|
||||||
|
end
|
||||||
|
|
||||||
|
local np2 = 0;
|
||||||
|
if( mirror_x ) then
|
||||||
|
np2 = handle_schematics.rotation_table[ n.paramtype2 ][ param2+1 ][ pos.brotate+1 ][ 2 ];
|
||||||
|
elseif( mirror_z ) then
|
||||||
|
np2 = handle_schematics.rotation_table[ n.paramtype2 ][ param2+1 ][ pos.brotate+1 ][ 3 ];
|
||||||
|
else
|
||||||
|
np2 = handle_schematics.rotation_table[ n.paramtype2 ][ param2+1 ][ pos.brotate+1 ][ 1 ];
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
local param2list = handle_schematics.get_param2_rotated( n.paramtype2, param2);
|
||||||
|
local np2 = param2list[ pos.brotate + 1];
|
||||||
|
-- mirror
|
||||||
|
if( mirror_x ) then
|
||||||
|
if( #param2list==5) then
|
||||||
|
np2 = handle_schematics.mirror_facedir[ ((pos.brotate+1)%2)+1 ][ np2+1 ];
|
||||||
|
elseif( #param2list<5
|
||||||
|
and ((pos.brotate%2==1 and (np2==4 or np2==5))
|
||||||
|
or (pos.brotate%2==0 and (np2==2 or np2==3)))) then
|
||||||
|
np2 = param2list[ (pos.brotate + 2)%4 +1];
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( mirror_z ) then
|
||||||
|
if( #param2list==5) then
|
||||||
|
np2 = handle_schematics.mirror_facedir[ (pos.brotate %2)+1 ][ np2+1 ];
|
||||||
|
elseif( #param2list<5
|
||||||
|
and ((pos.brotate%2==0 and (np2==4 or np2==5))
|
||||||
|
or (pos.brotate%2==1 and (np2==2 or np2==3)))) then
|
||||||
|
np2 = param2list[ (pos.brotate + 2)%4 +1];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
|
param2_data[a:index(ax, ay, az)] = np2;
|
||||||
|
else
|
||||||
|
param2_data[a:index(ax, ay, az)] = t[2];
|
||||||
|
end
|
||||||
|
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
|
||||||
|
local res = handle_schematics.mg_drop_moresnow( ax, az, y_top, y_bottom-1, a, data, param2_data);
|
||||||
|
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
|
||||||
|
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 );
|
||||||
|
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 );
|
||||||
|
--print('REPLACEMENTS: '..minetest.serialize( replacements.table )..' CHEST: '..tostring( minetest.get_name_from_content_id( cid.c_chest ))); -- TODO
|
||||||
|
|
||||||
|
local extranodes = {}
|
||||||
|
local extra_calls = { on_constr = {}, trees = {}, chests = {}, signs = {}, traders = {} };
|
||||||
|
|
||||||
|
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
|
||||||
|
local road_material = mg_villages.road_node;
|
||||||
|
if( pos.road_material ) then
|
||||||
|
road_material = pos.road_material;
|
||||||
|
end
|
||||||
|
generate_building(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, i, village_id, nil, road_material, true )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
--
|
||||||
|
handle_schematics.place_building_using_voxelmanip = function( pos, binfo, replacement_list)
|
||||||
|
|
||||||
|
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},
|
||||||
|
{x = pos.x+pos.bsizex, y = pos.y+binfo.ysize, z = pos.z+pos.bsizez} -- TODO
|
||||||
|
)
|
||||||
|
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 );
|
||||||
|
|
||||||
|
-- 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_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 = handle_schematics.get_content_id_replaced( 'mg_villages:plotmarker', replacements );
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
-- for roads
|
||||||
|
cid.c_sign = handle_schematics.get_content_id_replaced( 'default:gravel', replacements );
|
||||||
|
|
||||||
|
local extranodes = {}
|
||||||
|
local extra_calls = { on_constr = {}, trees = {}, chests = {}, signs = {}, traders = {} };
|
||||||
|
|
||||||
|
-- last parameter false -> place dirt nodes instead of trying to keep the ground nodes
|
||||||
|
generate_building(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, pos.building_nr, pos.village_id, binfo, cid.c_gravel, false);
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
return { extranodes = extranodes, replacements = replacements.list, extra_calls = extra_calls };
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
handle_schematics.place_building_from_file = function( start_pos, end_pos, building_name, replacement_list, rotate, axis, mirror, no_plotmarker )
|
||||||
|
if( not( building_name )) then
|
||||||
|
return "No file name given. Cannot find the schematic.";
|
||||||
|
end
|
||||||
|
|
||||||
|
local binfo = handle_schematics.analyze_file( building_name, nil, nil );
|
||||||
|
if( not( binfo )) then
|
||||||
|
return "Failed to import schematic. Only .mts and .we are supported!";
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nodenames and scm_data_cache can be used directly;
|
||||||
|
-- the size dimensions need to be renamed
|
||||||
|
binfo.sizex = binfo.size.x;
|
||||||
|
binfo.sizez = binfo.size.z;
|
||||||
|
binfo.ysize = binfo.size.y;
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
local res = handle_schematics.place_building_using_voxelmanip( start_pos, binfo, replacement_list);
|
||||||
|
if( not(res) or not( res.extra_calls )) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- call on_construct where needed;
|
||||||
|
-- trees, chests and signs receive no special treatment here
|
||||||
|
for k, v in pairs( res.extra_calls.on_constr ) do
|
||||||
|
local node_name = minetest.get_name_from_content_id( k );
|
||||||
|
if( minetest.registered_nodes[ node_name ].on_construct ) then
|
||||||
|
for _, pos in ipairs(v) do
|
||||||
|
minetest.registered_nodes[ node_name ].on_construct( pos );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
if( pos.bsizex > 2 and pos.bsizex > pos.bsizez) then
|
||||||
|
param2 = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
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
|
||||||
|
--]]
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
--[[
|
||||||
|
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
|
||||||
|
--]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if( minetest.get_modpath('moresnow' )) then
|
||||||
|
handle_schematics.moresnow_installed = true;
|
||||||
|
end
|
171
mods/a_mapgen_mods/handle_schematics/replacements_farming.lua
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
|
||||||
|
replacements_group['farming'] = {}
|
||||||
|
|
||||||
|
-- this contains a list of all found/available nodenames that may act as a replacement frming nodes
|
||||||
|
replacements_group['farming'].found = {};
|
||||||
|
-- contains a list of *all* known farming names - even of mods that may not be installed
|
||||||
|
replacements_group['farming'].all = {};
|
||||||
|
|
||||||
|
-- contains information about how a particular node is called if a particular farming mod is used;
|
||||||
|
replacements_group['farming'].data = {};
|
||||||
|
|
||||||
|
-- names of traders for the diffrent fruits
|
||||||
|
replacements_group['farming'].traders = {};
|
||||||
|
|
||||||
|
|
||||||
|
replacements_group['farming'].replace_material = function( replacements, old_material, new_material )
|
||||||
|
|
||||||
|
if( not( old_material ) or not( replacements_group['farming'].data[ old_material ])
|
||||||
|
or not( new_material ) or not( replacements_group['farming'].data[ new_material ])
|
||||||
|
or old_material == new_material ) then
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
local old_nodes = replacements_group['farming'].data[ old_material ];
|
||||||
|
local new_nodes = replacements_group['farming'].data[ new_material ];
|
||||||
|
for i=1,#old_nodes do
|
||||||
|
local old = old_nodes[i];
|
||||||
|
local new = old;
|
||||||
|
if( i<=#new_nodes and new_nodes[i] and minetest.registered_nodes[ new_nodes[i]] ) then
|
||||||
|
new = new_nodes[i];
|
||||||
|
local found = false;
|
||||||
|
for i,v in ipairs(replacements) do
|
||||||
|
if( v and v[1]==old ) then
|
||||||
|
v[2] = new;
|
||||||
|
found = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if( not( found )) then
|
||||||
|
table.insert( replacements, { old, new });
|
||||||
|
end
|
||||||
|
-- default to the last growth stage
|
||||||
|
elseif( i>#new_nodes and minetest.registered_nodes[ new_nodes[ #new_nodes ]]) then
|
||||||
|
table.insert( replacements, { old, new_nodes[ #new_nodes ] });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---------------------
|
||||||
|
-- internal functions
|
||||||
|
---------------------
|
||||||
|
replacements_group['farming'].add_material = function( fruit, fruit_item, prefix, seperator, postfix )
|
||||||
|
|
||||||
|
local is_loaded = false;
|
||||||
|
if( minetest.registered_items[ fruit_item ]
|
||||||
|
and minetest.registered_nodes[ prefix..fruit..seperator.."1"..postfix ] ) then
|
||||||
|
is_loaded = true;
|
||||||
|
table.insert( replacements_group['farming'].found, fruit_item );
|
||||||
|
end
|
||||||
|
table.insert( replacements_group['farming'].all, fruit_item );
|
||||||
|
|
||||||
|
local data = {};
|
||||||
|
-- handle seeds
|
||||||
|
if( minetest.registered_items[ prefix..fruit..'_seed' ]) then
|
||||||
|
data[1] = prefix..fruit..'_seed';
|
||||||
|
elseif( minetest.registered_items[ prefix..fruit..'seed' ]) then
|
||||||
|
data[1] = prefix..fruit..'seed';
|
||||||
|
else
|
||||||
|
data[1] = fruit_item;
|
||||||
|
end
|
||||||
|
for i=1,8 do
|
||||||
|
local node_name = prefix..fruit..seperator..tostring(i)..postfix;
|
||||||
|
if( is_loaded and minetest.registered_nodes[ node_name ]) then
|
||||||
|
table.insert( data, node_name );
|
||||||
|
-- if the mod is not loaded, we do not know how many growth stages it has;
|
||||||
|
-- in order to be on the safe side, store them all
|
||||||
|
elseif( not( is_loaded )) then
|
||||||
|
table.insert( data, node_name );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- the last plant stage (the one that gives the fruit) usually has no number
|
||||||
|
local node_name = prefix..fruit;
|
||||||
|
if( is_loaded and minetest.registered_nodes[ node_name ]) then
|
||||||
|
table.insert( data, node_name );
|
||||||
|
elseif( not( is_loaded )) then
|
||||||
|
table.insert( data, node_name );
|
||||||
|
end
|
||||||
|
replacements_group['farming'].data[ fruit_item ] = data;
|
||||||
|
|
||||||
|
-- farming nodes do not count as ground (except for soil - which is not handled here)
|
||||||
|
local c_ignore = minetest.get_content_id( 'ignore' );
|
||||||
|
for _,v in ipairs( data ) do
|
||||||
|
local id = minetest.get_content_id( v );
|
||||||
|
if( id and id ~= c_ignore ) then
|
||||||
|
replacements_group.node_is_ground[ id ] = false;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if( is_loaded and minetest.get_modpath('mobf_trader') and mobf_trader and mobf_trader.add_trader ) then
|
||||||
|
|
||||||
|
-- TODO: use replacements for the payments where needed
|
||||||
|
local goods = {
|
||||||
|
{ fruit_item.." 1", "default:coal_lump 3", "default:wood 8"},
|
||||||
|
{ fruit_item.." 10", "default:steel_ingot 2", "default:chest_locked 1"}};
|
||||||
|
if( fruit_item ~= data[1] ) then
|
||||||
|
table.insert( goods, { data[1].." 1", "farming:scarecrow", "farming:scarecrow_light 1"});
|
||||||
|
table.insert( goods, { data[1].." 2", "default:dirt 20", "default:bucket_water", "default:steel_ingot 4", "default:leaves 99" });
|
||||||
|
end
|
||||||
|
table.insert( goods, {"farming:hoe_wood 1","default:wood 10", "default:cobble 10"});
|
||||||
|
|
||||||
|
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||||
|
"farmer growing "..fruit.."s", -- not always the right grammatical form
|
||||||
|
fruit.."_farmer_v",
|
||||||
|
goods,
|
||||||
|
{ "farmer" },
|
||||||
|
{'kuhhaendler.png', 'bauer_in_sonntagskleidung.png', 'baeuerin.png', 'wheat_farmer_by_addi.png', 'tomatenhaendler.png'}
|
||||||
|
);
|
||||||
|
|
||||||
|
replacements_group['farming'].traders[ fruit_item ] = fruit..'_farmer_v';
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- create a list of all available fruit types
|
||||||
|
replacements_group['farming'].construct_farming_type_list = function()
|
||||||
|
|
||||||
|
-- farming from minetest_game
|
||||||
|
replacements_group['farming'].add_material( 'wheat', 'farming:wheat', 'farming:', '_', '' );
|
||||||
|
replacements_group['farming'].add_material( 'cotton', 'farming:cotton', 'farming:', '_', '' );
|
||||||
|
replacements_group['farming'].add_material( 'pumpkin','farming:pumpkin', 'farming:', '_', '' );
|
||||||
|
|
||||||
|
-- RealTest
|
||||||
|
replacements_group['farming'].add_material( 'flax', 'farming:string', 'farming:', '_', '' );
|
||||||
|
replacements_group['farming'].add_material( 'spelt', 'farming:wheat', 'farming:', '_', '' );
|
||||||
|
replacements_group['farming'].add_material( 'soy', 'farming:soy', 'farming:', '_', '' );
|
||||||
|
|
||||||
|
|
||||||
|
-- diffrent versions of farming_plus:
|
||||||
|
-- PilzAdam: https://forum.minetest.net/viewtopic.php?t=2787
|
||||||
|
-- TenPlus1: https://forum.minetest.net/viewtopic.php?t=9019
|
||||||
|
-- MTDad: https://forum.minetest.net/viewtopic.php?t=10187
|
||||||
|
local fruits = { 'strawberry', 'raspberry',
|
||||||
|
'carrot', 'rhubarb', 'cucumber',
|
||||||
|
'pumpkin', 'melon',
|
||||||
|
'orange', 'lemon', 'peach', 'walnut',
|
||||||
|
'potato','potatoe', -- diffrent mods spell them diffrently
|
||||||
|
'tomato', 'corn'
|
||||||
|
};
|
||||||
|
for i,fruit in ipairs( fruits ) do
|
||||||
|
if( minetest.registered_nodes[ 'farming_plus:'..fruit ]
|
||||||
|
and minetest.registered_nodes[ 'farming_plus:'..fruit..'_1' ]
|
||||||
|
and minetest.registered_items[ 'farming_plus:'..fruit..'_item' ] ) then
|
||||||
|
replacements_group['farming'].add_material( fruit, 'farming_plus:'..fruit..'_item', 'farming_plus:', '_', '' );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- coffee beans from farming_plus/farming_plusplus
|
||||||
|
replacements_group['farming'].add_material( 'coffee', 'farming_plus:coffee_beans', 'farming_plus:', '_', '' );
|
||||||
|
|
||||||
|
-- Docfarming: https://forum.minetest.net/viewtopic.php?t=3948
|
||||||
|
fruits = {'carrot','corn','potato','raspberry'};
|
||||||
|
for i,fruit in ipairs( fruits ) do
|
||||||
|
replacements_group['farming'].add_material( fruit, 'docfarming:'..fruit, 'docfarming:', '', '' );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- create the list of known farming fruits
|
||||||
|
replacements_group['farming'].construct_farming_type_list();
|
@ -0,0 +1,21 @@
|
|||||||
|
-- mapgen based replacements work best using a table, while minetest.place_schematic(..) based spawning needs a list
|
||||||
|
handle_schematics.get_replacement_table = function( housetype, pr, replacements )
|
||||||
|
|
||||||
|
local rtable = {};
|
||||||
|
local ids = {};
|
||||||
|
if( not( replacements ) and mg_villages and mg_villages.get_replacement_list) then
|
||||||
|
replacements = mg_villages.get_replacement_list( housetype, pr );
|
||||||
|
end
|
||||||
|
-- it is very problematic if the torches on houses melt snow and cause flooding; thus, we use a torch that is not hot
|
||||||
|
if( minetest.registered_nodes[ 'mg_villages:torch']) then
|
||||||
|
table.insert( replacements, {'default:torch', 'mg_villages:torch'});
|
||||||
|
end
|
||||||
|
for i,v in ipairs( replacements ) do
|
||||||
|
if( v and #v == 2 ) then
|
||||||
|
rtable[ v[1] ] = v[2];
|
||||||
|
ids[ minetest.get_content_id( v[1] )] = minetest.get_content_id( v[2] );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return { table = rtable, list = replacements, ids = ids };
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,82 @@
|
|||||||
|
replacements_group['realtest'] = {}
|
||||||
|
|
||||||
|
-- parameter: replacements, name_in_default, name_in_realtest, to_realtest=true/false
|
||||||
|
replacements_group['realtest'].stairs = function( repl, def, rt, to_realtest)
|
||||||
|
if( to_realtest ) then
|
||||||
|
if( def ~= rt ) then
|
||||||
|
table.insert( repl, {'default:'..def, 'default:'..rt});
|
||||||
|
end
|
||||||
|
table.insert( repl, {'stairs:stair_'..def, 'default:'..rt..'_stair'});
|
||||||
|
table.insert( repl, {'stairs:slab_'..def, 'default:'..rt..'_slab'});
|
||||||
|
else
|
||||||
|
if( def ~= rt ) then
|
||||||
|
table.insert( repl, {'default:'..rt, 'default:'..def});
|
||||||
|
end
|
||||||
|
table.insert( repl, {'default:'..rt..'_stair', 'stairs:stair_'..def});
|
||||||
|
table.insert( repl, {'default:'..rt..'_stair_upside_down','stairs:stair_'..def});
|
||||||
|
-- upside-down-slab
|
||||||
|
table.insert( repl, {'default:'..rt..'_slab_r', 'stairs:slab_'..def});
|
||||||
|
table.insert( repl, {'default:'..rt..'_slab', 'stairs:slab_'..def});
|
||||||
|
end
|
||||||
|
return repl;
|
||||||
|
end
|
||||||
|
|
||||||
|
replacements_group['realtest'].replace = function( replacements )
|
||||||
|
|
||||||
|
local repl = {};
|
||||||
|
local to_realtest = false;
|
||||||
|
if( not( minetest.registered_nodes[ 'default:furnace' ])
|
||||||
|
and minetest.registered_nodes[ 'oven:oven' ]) then
|
||||||
|
to_realtest = true;
|
||||||
|
elseif( minetest.registered_nodes[ 'default:furnace' ]
|
||||||
|
and not( minetest.registered_nodes[ 'oven:oven' ])) then
|
||||||
|
to_realtest = false;
|
||||||
|
else
|
||||||
|
-- else no replacements required
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
replacements_group['realtest'].stairs( repl, 'stone', 'stone', to_realtest );
|
||||||
|
replacements_group['realtest'].stairs( repl, 'cobble', 'stone_flat', to_realtest );
|
||||||
|
replacements_group['realtest'].stairs( repl, 'stonebrick', 'stone_bricks', to_realtest );
|
||||||
|
replacements_group['realtest'].stairs( repl, 'desert_stone', 'desert_stone', to_realtest );
|
||||||
|
replacements_group['realtest'].stairs( repl, 'desert_cobble', 'desert_stone_flat', to_realtest );
|
||||||
|
replacements_group['realtest'].stairs( repl, 'desert_stonebrick', 'desert_stone_bricks',to_realtest );
|
||||||
|
replacements_group['realtest'].stairs( repl, 'brick', 'brick', to_realtest );
|
||||||
|
|
||||||
|
if( to_realtest ) then
|
||||||
|
table.insert( repl, {'default:furnace', 'oven:oven'});
|
||||||
|
table.insert( repl, {'default:clay', 'grounds:clay'});
|
||||||
|
-- Realtest does not know about these nodes yet
|
||||||
|
table.insert( repl, {'farming:soil_wet', 'farming:soil'});
|
||||||
|
table.insert( repl, {'farming:desert_sand_soil', 'farming:soil'});
|
||||||
|
table.insert( repl, {'farming:desert_sand_soil_wet','farming:soil'});
|
||||||
|
for i=1,5 do
|
||||||
|
table.insert( repl, {'default:grass_'..i,'air' });
|
||||||
|
end
|
||||||
|
table.insert( repl, {'default:apple', 'air' });
|
||||||
|
table.insert( repl, {'default:obsidian_glass', 'default:glass' });
|
||||||
|
else
|
||||||
|
table.insert( repl, {'oven:oven', 'default:furnace'});
|
||||||
|
table.insert( repl, {'grounds:clay', 'default:clay'});
|
||||||
|
table.insert( repl, {'farming:soil', 'farming:soil_wet'});
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
for i,v in ipairs( repl ) do
|
||||||
|
if( v and v[2] and minetest.registered_nodes[ v[2]] ) then
|
||||||
|
local found = false;
|
||||||
|
for j,w in ipairs( replacements ) do
|
||||||
|
if( w and w[1] and w[1]==v[1] ) then
|
||||||
|
w[2] = v[2];
|
||||||
|
found = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if( not( found )) then
|
||||||
|
table.insert( replacements, {v[1],v[2]} );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
110
mods/a_mapgen_mods/handle_schematics/replacements_roof.lua
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
replacements_group['roof'] = {}
|
||||||
|
|
||||||
|
-- this contains a list of all found/available nodenames that may act as a replacement frming nodes
|
||||||
|
replacements_group['roof'].found = {};
|
||||||
|
-- contains a list of *all* known roof names - even of mods that may not be installed
|
||||||
|
replacements_group['roof'].all = {};
|
||||||
|
|
||||||
|
-- contains information about how a particular node is called if a particular roof mod is used;
|
||||||
|
replacements_group['roof'].data = {};
|
||||||
|
|
||||||
|
|
||||||
|
replacements_group['roof'].replace_material = function( replacements, old_material, new_material )
|
||||||
|
|
||||||
|
if( not( old_material ) or not( replacements_group['roof'].data[ old_material ])
|
||||||
|
or not( new_material ) or not( replacements_group['roof'].data[ new_material ])
|
||||||
|
or old_material == new_material ) then
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
local old_nodes = replacements_group['roof'].data[ old_material ];
|
||||||
|
local new_nodes = replacements_group['roof'].data[ new_material ];
|
||||||
|
for i=1,#old_nodes do
|
||||||
|
local old = old_nodes[i];
|
||||||
|
local new = old;
|
||||||
|
if( i<=#new_nodes and new_nodes[i] and minetest.registered_nodes[ new_nodes[i]] ) then
|
||||||
|
new = new_nodes[i];
|
||||||
|
local found = false;
|
||||||
|
for i,v in ipairs(replacements) do
|
||||||
|
if( v and v[1]==old ) then
|
||||||
|
v[2] = new;
|
||||||
|
found = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if( not( found )) then
|
||||||
|
table.insert( replacements, { old, new });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---------------------
|
||||||
|
-- internal functions
|
||||||
|
---------------------
|
||||||
|
replacements_group['roof'].add_material = function( nodelist )
|
||||||
|
|
||||||
|
local is_loaded = false;
|
||||||
|
if( minetest.registered_items[ nodelist[1] ] ) then
|
||||||
|
is_loaded = true;
|
||||||
|
table.insert( replacements_group['roof'].found, nodelist[1] );
|
||||||
|
end
|
||||||
|
table.insert( replacements_group['roof'].all, nodelist[1]);
|
||||||
|
|
||||||
|
replacements_group['roof'].data[ nodelist[1] ] = nodelist;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- create a list of all available fruit types
|
||||||
|
replacements_group['roof'].construct_roof_type_list = function()
|
||||||
|
|
||||||
|
-- roof from cottages
|
||||||
|
local roofs = {'straw', 'reet', 'wood', 'slate', 'red', 'brown', 'black'};
|
||||||
|
for i,v in ipairs( roofs ) do
|
||||||
|
replacements_group['roof'].add_material( {
|
||||||
|
'cottages:roof_connector_'..v,
|
||||||
|
'cottages:roof_flat_'..v,
|
||||||
|
'', -- no full block available
|
||||||
|
'cottages:roof_'..v
|
||||||
|
} );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- from dryplants
|
||||||
|
roofs = {'reed', 'wetreed'};
|
||||||
|
for i,v in ipairs( roofs ) do
|
||||||
|
replacements_group['roof'].add_material( {
|
||||||
|
'dryplants:'..v..'_roof',
|
||||||
|
'dryplants:'..v..'_slab',
|
||||||
|
'dryplants:'..v,
|
||||||
|
'dryplants:'..v..'_roof',
|
||||||
|
'dryplants:'..v..'_roof_corner',
|
||||||
|
'dryplants:'..v..'_roof_corner_2'
|
||||||
|
} );
|
||||||
|
end
|
||||||
|
-- roof from homedecor
|
||||||
|
roofs = {'wood', 'terracotta', 'asphalt', 'glass'};
|
||||||
|
for i,v in ipairs( roofs ) do
|
||||||
|
replacements_group['roof'].add_material( {
|
||||||
|
'homedecor:shingle_side_'..v,
|
||||||
|
'homedecor:shingles_'..v,
|
||||||
|
'',
|
||||||
|
'homedecor:shingles_'..v,
|
||||||
|
'homedecor:shingle_inner_corner_'..v,
|
||||||
|
'homedecor:shingle_outer_corner_'..v,
|
||||||
|
} );
|
||||||
|
end
|
||||||
|
|
||||||
|
replacements_group['roof'].data[ 'homedecor:shingle_side_glass' ][2] = 'homedecor:skylight';
|
||||||
|
replacements_group['roof'].data[ 'homedecor:shingle_side_glass' ][4] = 'homedecor:skylight';
|
||||||
|
replacements_group['roof'].data[ 'homedecor:shingle_side_asphalt'][3] = 'streets:asphalt';
|
||||||
|
|
||||||
|
-- TODO: slopes from technic or other slopes mods?
|
||||||
|
end
|
||||||
|
|
||||||
|
-- create the list of known roof fruits
|
||||||
|
replacements_group['roof'].construct_roof_type_list();
|
234
mods/a_mapgen_mods/handle_schematics/replacements_wood.lua
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
replacements_group['wood'] = {}
|
||||||
|
|
||||||
|
-- this contains a list of all found/available nodenames that may act as a replacement for default:wood
|
||||||
|
replacements_group['wood'].found = {};
|
||||||
|
-- contains a list of *all* known wood names - even of mods that may not be installed
|
||||||
|
replacements_group['wood'].all = {};
|
||||||
|
|
||||||
|
-- contains information about how a particular node is called if a particular wood is used;
|
||||||
|
replacements_group['wood'].data = {};
|
||||||
|
|
||||||
|
-- names of traders for the diffrent wood types
|
||||||
|
replacements_group['wood'].traders = {};
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
-- external function; call it in order to replace old_wood with new_wood;
|
||||||
|
-- other nodes (trees, saplings, fences, doors, ...) are replaced accordingly,
|
||||||
|
-- depending on what new_wood has to offer
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
replacements_group['wood'].replace_material = function( replacements, old_wood, new_wood )
|
||||||
|
|
||||||
|
if( not( old_wood ) or not( replacements_group['wood'].data[ old_wood ])
|
||||||
|
or not( new_wood ) or not( replacements_group['wood'].data[ new_wood ])
|
||||||
|
or old_wood == new_wood ) then
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
local old_nodes = replacements_group['wood'].data[ old_wood ];
|
||||||
|
local new_nodes = replacements_group['wood'].data[ new_wood ];
|
||||||
|
for i=3,#old_nodes do
|
||||||
|
local old = old_nodes[i];
|
||||||
|
local new = old;
|
||||||
|
if( i<=#new_nodes and new_nodes[i] and minetest.registered_nodes[ new_nodes[i]] ) then
|
||||||
|
new = new_nodes[i];
|
||||||
|
local found = false;
|
||||||
|
for i,v in ipairs(replacements) do
|
||||||
|
if( v and v[1]==old ) then
|
||||||
|
v[2] = new;
|
||||||
|
found = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if( not( found )) then
|
||||||
|
table.insert( replacements, { old, new });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---------------------
|
||||||
|
-- internal functions
|
||||||
|
---------------------
|
||||||
|
-- wood (and its corresponding tree trunk) is a very good candidate for replacement in most houses
|
||||||
|
-- helper function for replacements_group['wood'].get_wood_type_list
|
||||||
|
replacements_group['wood'].add_material = function( candidate_list, mod_prefix, w_pre, w_post, t_pre, t_post, l_pre, l_post,
|
||||||
|
s_pre, s_post, stair_pre, stair_post, slab_pre, slab_post,
|
||||||
|
fence_pre, fence_post, gate_pre, gate_post )
|
||||||
|
if( not( candidate_list )) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
for _,v in ipairs( candidate_list ) do
|
||||||
|
local is_loaded = false;
|
||||||
|
local wood_name = mod_prefix..w_pre..v..w_post;
|
||||||
|
-- create a complete list of all possible wood names
|
||||||
|
table.insert( replacements_group['wood'].all, wood_name );
|
||||||
|
-- create a list of all *installed* wood types
|
||||||
|
if( minetest.registered_nodes[ wood_name ]) then
|
||||||
|
table.insert( replacements_group['wood'].found, wood_name );
|
||||||
|
is_loaded = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- there is no check if the node names created here actually exist
|
||||||
|
local data = { v, -- 1. base name of the node
|
||||||
|
mod_prefix, -- 2. mod name
|
||||||
|
wood_name, -- 3. replacement for default:wood
|
||||||
|
mod_prefix..t_pre..v..t_post, -- 4. " " for default:tree
|
||||||
|
mod_prefix..l_pre..v..l_post, -- 5. " " for default:leaves
|
||||||
|
mod_prefix..s_pre..v..s_post, -- 6. " " for default:sapling
|
||||||
|
stair_pre..v..stair_post, -- 7. " " for stairs:stair_wood
|
||||||
|
slab_pre..v..slab_post, -- 8. " " for stairs:slab_wood
|
||||||
|
fence_pre..v..fence_post, -- 9. " " for default:fence_wood
|
||||||
|
gate_pre..v..gate_post..'_open', -- 10. " " for cottages:gate_open
|
||||||
|
gate_pre..v..gate_post..'_closed',-- 11. " " for cottages:gate_closed
|
||||||
|
};
|
||||||
|
|
||||||
|
-- normal wood does have a number of nodes which might get replaced by more specialized wood types
|
||||||
|
if( mod_prefix=='default:' and v=='' ) then
|
||||||
|
local w = 'wood';
|
||||||
|
data[10] = 'cottages:gate_open';
|
||||||
|
data[11] = 'cottages:gate_closed';
|
||||||
|
data[12] = 'default:ladder';
|
||||||
|
data[13] = 'doors:door_'..w..'_t_1';
|
||||||
|
data[14] = 'doors:door_'..w..'_t_2';
|
||||||
|
data[15] = 'doors:door_'..w..'_b_1';
|
||||||
|
data[16] = 'doors:door_'..w..'_b_2';
|
||||||
|
data[17] = 'default:bookshelf';
|
||||||
|
data[18] = 'default:chest';
|
||||||
|
data[19] = 'default:chest_locked';
|
||||||
|
data[20] = 'stairs:stair_'..w..'upside_down';
|
||||||
|
data[21] = 'stairs:slab_'..w..'upside_down';
|
||||||
|
data[22] = 'doors:trapdoor_open';
|
||||||
|
data[23] = 'doors:trapdoor';
|
||||||
|
-- realtest has some further replacements
|
||||||
|
elseif( mod_prefix=='trees:' and w_post=='_planks' and t_post=='_log' ) then
|
||||||
|
data[12] = 'trees:'..v..'_ladder';
|
||||||
|
data[13] = 'doors:door_'..v..'_t_1';
|
||||||
|
data[14] = 'doors:door_'..v..'_t_2';
|
||||||
|
data[15] = 'doors:door_'..v..'_b_1';
|
||||||
|
data[16] = 'doors:door_'..v..'_b_2';
|
||||||
|
data[17] = 'decorations:bookshelf_'..v;
|
||||||
|
data[18] = 'trees:'..v..'_chest';
|
||||||
|
data[19] = 'trees:'..v..'_chest_locked';
|
||||||
|
data[20] = 'trees:'..v..'_planks_stair_upside_down';
|
||||||
|
data[21] = 'trees:'..v..'_planks_slab_upside_down';
|
||||||
|
data[22] = 'hatches:'..v..'_hatch_opened_top';
|
||||||
|
data[23] = 'hatches:'..v..'_hatch_opened_bottom';
|
||||||
|
end
|
||||||
|
replacements_group['wood'].data[ wood_name ] = data;
|
||||||
|
|
||||||
|
-- none of the wood nodes counts as ground
|
||||||
|
local c_ignore = minetest.get_content_id( 'ignore' );
|
||||||
|
for _,v in ipairs( data ) do
|
||||||
|
local id = minetest.get_content_id( v );
|
||||||
|
if( id and id ~= c_ignore ) then
|
||||||
|
replacements_group.node_is_ground[ id ] = false;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if( is_loaded and minetest.get_modpath('mobf_trader') and mobf_trader and mobf_trader.add_trader ) then
|
||||||
|
-- TODO: check if all offered payments exist
|
||||||
|
local goods = {
|
||||||
|
{ data[3].." 4", "default:dirt 24", "default:cobble 24"},
|
||||||
|
{ data[4].." 4", "default:apple 2", "default:coal_lump 4"},
|
||||||
|
{ data[4].." 8", "default:pick_stone 1", "default:axe_stone 1"},
|
||||||
|
{ data[4].." 12", "default:cobble 80", "default:steel_ingot 1"},
|
||||||
|
{ data[4].." 36", "bucket:bucket_empty 1", "bucket:bucket_water 1"},
|
||||||
|
{ data[4].." 42", "default:axe_steel 1", "default:mese_crystal 4"},
|
||||||
|
|
||||||
|
{ data[6].." 1", "default:mese 10", "default:steel_ingot 48"},
|
||||||
|
-- leaves are a cheaper way of getting saplings
|
||||||
|
{ data[5].." 10", "default:cobble 1", "default:dirt 2"}
|
||||||
|
};
|
||||||
|
|
||||||
|
mobf_trader.add_trader( mobf_trader.npc_trader_prototype,
|
||||||
|
"Trader of "..( v or "unknown" ).." wood",
|
||||||
|
v.."_wood_v",
|
||||||
|
goods,
|
||||||
|
{ "lumberjack" },
|
||||||
|
{ 'holzfaeller.png' }
|
||||||
|
);
|
||||||
|
|
||||||
|
replacements_group['wood'].traders[ wood_name ] = v..'_wood_v';
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: there are also upside-down variants sometimes
|
||||||
|
-- TODO: moreblocks - those may be installed and offer further replacements
|
||||||
|
|
||||||
|
-- create a list of all available wood types
|
||||||
|
replacements_group['wood'].construct_wood_type_list = function()
|
||||||
|
|
||||||
|
-- https://github.com/minetest/minetest_game
|
||||||
|
-- default tree and jungletree; no gates available
|
||||||
|
replacements_group['wood'].add_material( {'', 'jungle' }, 'default:', '','wood','', 'tree', '','leaves', '','sapling',
|
||||||
|
'stairs:stair_', 'wood', 'stairs:slab_', 'wood', 'default:fence_','wood', 'NONE', '' );
|
||||||
|
-- default:pine_needles instead of leaves; no gates available
|
||||||
|
replacements_group['wood'].add_material( {'pine' }, 'default:', '','wood','', 'tree', '','_needles','','_sapling',
|
||||||
|
'stairs:stair_', 'wood', 'stairs:slab_', 'wood', 'default:fence_','wood', 'NONE','' );
|
||||||
|
|
||||||
|
-- https://github.com/Novatux/mg
|
||||||
|
-- trees from nores mapgen
|
||||||
|
replacements_group['wood'].add_material( {'savanna', 'pine' },'mg:', '','wood','', 'tree', '','leaves', '','sapling',
|
||||||
|
'stairs:stair_','wood', 'stairs:slab_','wood', 'NONE','', 'NONE','');
|
||||||
|
|
||||||
|
|
||||||
|
-- https://github.com/VanessaE/moretrees
|
||||||
|
-- minus the jungletree (already in default)
|
||||||
|
local moretrees_treelist = {"beech","apple_tree","oak","sequoia","birch","palm","spruce","pine","willow","acacia","rubber_tree","fir" };
|
||||||
|
replacements_group['wood'].add_material( moretrees_treelist, 'moretrees:', '', '_planks', '','_trunk', '','_leaves','','_sapling',
|
||||||
|
'moretrees:stair_','_planks', 'moretrees:slab_','_planks', 'NONE','', 'NONE','');
|
||||||
|
|
||||||
|
|
||||||
|
-- https://github.com/tenplus1/ethereal
|
||||||
|
-- ethereal does not have a common naming convention for leaves
|
||||||
|
replacements_group['wood'].add_material( {'acacia','redwood'},'ethereal:', '','_wood', '','_trunk', '','_leaves', '','_sapling',
|
||||||
|
'stairs:stair_','_wood', 'stairs:slab_','_wood', 'ethereal:fence_','', 'ethereal:','gate');
|
||||||
|
-- frost has another sapling type...
|
||||||
|
replacements_group['wood'].add_material( {'frost'}, 'ethereal:', '','_wood', '','_tree', '','_leaves', '','_tree_sapling',
|
||||||
|
'stairs:stair_','_wood', 'stairs:slab_','_wood', 'ethereal:fence_','wood', 'ethereal:','woodgate' );
|
||||||
|
-- those tree types do not use typ_leaves, but typleaves instead...
|
||||||
|
replacements_group['wood'].add_material( {'yellow'}, 'ethereal:', '','_wood', '','_trunk', '','leaves', '','_tree_sapling',
|
||||||
|
'stairs:stair_','_wood', 'stairs:slab_','_wood', 'ethereal:fence_','wood', 'ethereal:','gate' );
|
||||||
|
-- banana has a diffrent fence type....
|
||||||
|
replacements_group['wood'].add_material( {'banana'}, 'ethereal:', '','_wood', '','_trunk', '','leaves', '','_tree_sapling',
|
||||||
|
'stairs:stair_','_wood', 'stairs:slab_','_wood', 'ethereal:fence_', '', 'ethereal:','gate' );
|
||||||
|
-- palm has another name for the sapling again...
|
||||||
|
replacements_group['wood'].add_material( {'palm'}, 'ethereal:', '','_wood', '','_trunk', '','leaves', '','_sapling',
|
||||||
|
'stairs:stair_','_wood', 'stairs:slab_','_wood', 'ethereal:fence_', '', 'ethereal:','gate' );
|
||||||
|
-- the leaves are called willow_twig here...
|
||||||
|
replacements_group['wood'].add_material( {'willow'}, 'ethereal:', '','_wood', '','_trunk', '','_twig', '','_sapling',
|
||||||
|
'stairs:stair_','_wood', 'stairs:slab_','_wood', 'ethereal:fence_', '', 'ethereal:','gate' );
|
||||||
|
-- mushroom has its own name; it works quite well as a wood replacement; the red cap is used as leaves
|
||||||
|
-- the stairs are also called slightly diffrently (end in _trunk instead of _wood)
|
||||||
|
replacements_group['wood'].add_material( {'mushroom'}, 'ethereal:', '','_pore', '','_trunk', '','', '','_sapling',
|
||||||
|
'stairs:stair_','_trunk', 'stairs:slab_','_trunk', 'ethereal:fence_', '', 'ethereal:','gate' );
|
||||||
|
|
||||||
|
|
||||||
|
-- https://github.com/VanessaE/realtest_game
|
||||||
|
local realtest_trees = {'ash','aspen','birch','maple','chestnut','pine','spruce'};
|
||||||
|
replacements_group['wood'].add_material( realtest_trees, 'trees:', '','_planks', '','_log', '','_leaves', '','_sapling',
|
||||||
|
'trees:','_planks_stair', 'trees:','_planks_slab', 'fences:','_fence', 'NONE','' );
|
||||||
|
|
||||||
|
|
||||||
|
-- https://github.com/Gael-de-Sailly/Forest
|
||||||
|
local forest_trees = {'oak','birch','willow','fir','mirabelle','cherry','plum','beech','ginkgo','lavender'};
|
||||||
|
replacements_group['wood'].add_material( forest_trees, 'forest:', '', '_wood', '','_tree', '','_leaves', '','_sapling',
|
||||||
|
'stairs:stair_','_wood', 'stairs:slab_','_wood', 'NONE','', 'NONE','' );
|
||||||
|
|
||||||
|
-- https://github.com/bas080/trees
|
||||||
|
replacements_group['wood'].add_material( {'mangrove','palm','conifer'},'trees:', 'wood_','', 'tree_','', 'leaves_','', 'sapling_','',
|
||||||
|
'stairs:stair_','_wood', 'stairs:slab_','_wood', 'NONE','', 'NONE','' );
|
||||||
|
|
||||||
|
|
||||||
|
-- https://github.com/PilzAdam/farming_plus
|
||||||
|
-- TODO: this does not come with its own wood... banana and cocoa trees (only leaves, sapling and fruit)
|
||||||
|
-- TODO: farming_plus:TREETYP_sapling farming_plus:TREETYP_leaves farming_plus:TREETYP
|
||||||
|
-- TODO: in general: add fruits as replacements for apples
|
||||||
|
end
|
||||||
|
|
||||||
|
-- actually construct the data structure once
|
||||||
|
replacements_group['wood'].construct_wood_type_list();
|
||||||
|
|
114
mods/a_mapgen_mods/handle_schematics/rotate.lua
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
local rotate_facedir = function(facedir)
|
||||||
|
return ({1, 2, 3, 0,
|
||||||
|
13, 14, 15, 12,
|
||||||
|
17, 18, 19, 16,
|
||||||
|
9, 10, 11, 8,
|
||||||
|
5, 6, 7, 4,
|
||||||
|
21, 22, 23, 20})[facedir+1]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- accessd through handle_schematics.mirror_facedir[ (rotation%2)+1 ][ facedir+1 ]
|
||||||
|
handle_schematics.mirror_facedir =
|
||||||
|
{{ 2, 1, 0, 3, -- 0, 1, 2, 3
|
||||||
|
8, 9, 10, 11, -- 4, 5, 6, 7
|
||||||
|
4, 5, 6, 7, -- 8, 9,10,11
|
||||||
|
12, 13, 14, 15, --12,13,14,15
|
||||||
|
16, 17, 18, 19, --16,17,18,19
|
||||||
|
22, 21, 20, 23 --20,21,22,23
|
||||||
|
},
|
||||||
|
{ 0, 3, 2, 1, -- 0, 1, 2, 3
|
||||||
|
4, 7, 6, 5, -- 4, 5, 6, 7
|
||||||
|
8, 9, 10, 11, -- 8, 9,10,11
|
||||||
|
16, 17, 18, 19, --12,13,14,15
|
||||||
|
12, 15, 14, 13, --16,17,18,19
|
||||||
|
20, 23, 22, 21 --20,21,22,23
|
||||||
|
}};
|
||||||
|
|
||||||
|
local rotate_wallmounted = function(wallmounted)
|
||||||
|
return ({0, 1, 5, 4, 2, 3})[wallmounted+1]
|
||||||
|
end
|
||||||
|
|
||||||
|
handle_schematics.get_param2_rotated = function( paramtype2, p2 )
|
||||||
|
local p2r = {};
|
||||||
|
p2r[ 1 ] = p2;
|
||||||
|
if( paramtype2 == 'wallmounted' ) then
|
||||||
|
for i = 2,4 do
|
||||||
|
p2r[ i ] = rotate_wallmounted( p2r[ i-1 ]);
|
||||||
|
end
|
||||||
|
elseif( paramtype2 == 'facedir' ) then
|
||||||
|
for i = 2,4 do
|
||||||
|
p2r[ i ] = rotate_facedir( p2r[ i-1 ]);
|
||||||
|
end
|
||||||
|
p2r[5]=1; -- indicate that it is wallmounted
|
||||||
|
else
|
||||||
|
return { p2, p2, p2, p2 };
|
||||||
|
end
|
||||||
|
return p2r;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
handle_schematics.mirrored_node = {};
|
||||||
|
|
||||||
|
handle_schematics.add_mirrored_node_type = function( name, mirrored_name )
|
||||||
|
handle_schematics.mirrored_node[ name ] = mirrored_name;
|
||||||
|
local id = minetest.get_content_id( name );
|
||||||
|
local id_mi = minetest.get_content_id( mirrored_name );
|
||||||
|
local c_ignore = minetest.get_content_id( 'ignore' );
|
||||||
|
if( id and id_mi and id ~= c_ignore and id_mi ~= c_ignore ) then
|
||||||
|
handle_schematics.mirrored_node[ id ] = id_mi;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local door_materials = {'wood','steel','glass','obsidian_glass'};
|
||||||
|
for _,material in ipairs( door_materials ) do
|
||||||
|
handle_schematics.add_mirrored_node_type( 'doors:door_'..material..'_b_1', 'doors:door_'..material..'_b_2' );
|
||||||
|
handle_schematics.add_mirrored_node_type( 'doors:door_'..material..'_t_1', 'doors:door_'..material..'_t_2' );
|
||||||
|
handle_schematics.add_mirrored_node_type( 'doors:door_'..material..'_b_2', 'doors:door_'..material..'_b_1' );
|
||||||
|
handle_schematics.add_mirrored_node_type( 'doors:door_'..material..'_t_2', 'doors:door_'..material..'_t_1' );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
handle_schematics.rotation_table = {};
|
||||||
|
handle_schematics.rotation_table[ 'facedir' ] = {};
|
||||||
|
handle_schematics.rotation_table[ 'wallmounted' ] = {};
|
||||||
|
|
||||||
|
|
||||||
|
for paramtype2,v in pairs( handle_schematics.rotation_table ) do
|
||||||
|
for param2 = 0,23 do
|
||||||
|
|
||||||
|
if( param2 < 6 or paramtype2 == 'facedir' ) then
|
||||||
|
local param2list = handle_schematics.get_param2_rotated( paramtype2, param2);
|
||||||
|
|
||||||
|
handle_schematics.rotation_table[ paramtype2 ][ param2+1 ] = {};
|
||||||
|
|
||||||
|
for rotation = 0,3 do
|
||||||
|
local np2 = param2list[ rotation + 1];
|
||||||
|
local mirror_x = np2;
|
||||||
|
local mirror_z = np2;
|
||||||
|
|
||||||
|
-- mirror_x
|
||||||
|
if( #param2list==5) then
|
||||||
|
mirror_x = handle_schematics.mirror_facedir[ (( rotation +1)%2)+1 ][ np2+1 ];
|
||||||
|
elseif( #param2list<5
|
||||||
|
and (( rotation%2==1 and (np2==4 or np2==5))
|
||||||
|
or ( rotation%2==0 and (np2==2 or np2==3)))) then
|
||||||
|
mirror_x = param2list[ ( rotation + 2)%4 +1];
|
||||||
|
end
|
||||||
|
|
||||||
|
-- mirror_z
|
||||||
|
if( #param2list==5) then
|
||||||
|
mirror_z = handle_schematics.mirror_facedir[ (rotation %2)+1 ][ np2+1 ];
|
||||||
|
elseif( #param2list<5
|
||||||
|
and (( rotation%2==0 and (np2==4 or np2==5))
|
||||||
|
or ( rotation%2==1 and (np2==2 or np2==3)))) then
|
||||||
|
mirror_z = param2list[ ( rotation + 2)%4 +1];
|
||||||
|
end
|
||||||
|
|
||||||
|
handle_schematics.rotation_table[ paramtype2 ][ param2+1 ][ rotation+1 ] = { np2, mirror_x, mirror_z };
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
91
mods/a_mapgen_mods/handle_schematics/save_restore.lua
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
|
||||||
|
-- reserve the namespace
|
||||||
|
save_restore = {}
|
||||||
|
|
||||||
|
-- TODO: if this gets more versatile, add sanity checks for filename
|
||||||
|
-- TODO: apart from allowing filenames, schems/<filename> also needs to be allowed
|
||||||
|
|
||||||
|
-- TODO: save and restore ought to be library functions and not implemented in each individual mod!
|
||||||
|
save_restore.save_data = function( filename, data )
|
||||||
|
|
||||||
|
local path = minetest.get_worldpath()..'/'..filename;
|
||||||
|
|
||||||
|
local file = io.open( path, 'w' );
|
||||||
|
if( file ) then
|
||||||
|
file:write( minetest.serialize( data ));
|
||||||
|
file:close();
|
||||||
|
else
|
||||||
|
print("[save_restore] Error: Savefile '"..tostring( path ).."' could not be written.");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
save_restore.restore_data = function( filename )
|
||||||
|
local path = minetest.get_worldpath()..'/'..filename;
|
||||||
|
local file = io.open( path, 'r' );
|
||||||
|
if( file ) then
|
||||||
|
local data = file:read("*all");
|
||||||
|
file:close();
|
||||||
|
return minetest.deserialize( data );
|
||||||
|
else
|
||||||
|
print("[save_restore] Error: Savefile '"..tostring( path ).."' not found.");
|
||||||
|
return {}; -- return empty table
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
save_restore.file_exists = function( filename )
|
||||||
|
|
||||||
|
local path = minetest.get_worldpath()..'/'..filename;
|
||||||
|
|
||||||
|
local file = save_restore.file_access( path, 'r' );
|
||||||
|
if( file ) then
|
||||||
|
file:close();
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
save_restore.create_directory = function( filename )
|
||||||
|
|
||||||
|
local path = minetest.get_worldpath()..'/'..filename;
|
||||||
|
|
||||||
|
if( not( save_restore.file_exists( filename ))) then
|
||||||
|
if( minetest.mkdir ) then
|
||||||
|
minetest.mkdir( minetest.get_worldpath().."/schems");
|
||||||
|
else
|
||||||
|
os.execute("mkdir \""..minetest.get_worldpath().."/schems".. "\"");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- we only need the function io.open in a version that can read schematic files from diffrent places,
|
||||||
|
-- even if a secure environment is enforced; this does require an exception for the mod
|
||||||
|
local ie_io_open = io.open;
|
||||||
|
if( minetest.request_insecure_environment ) then
|
||||||
|
local ie, req_ie = _G, minetest.request_insecure_environment
|
||||||
|
if req_ie then ie = req_ie() end
|
||||||
|
if ie then
|
||||||
|
ie_io_open = ie.io.open;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- only a certain type of files can be read and written
|
||||||
|
save_restore.file_access = function( path, params )
|
||||||
|
if( (params=='r' or params=='rb')
|
||||||
|
and ( string.find( path, '.mts', -4 )
|
||||||
|
or string.find( path, '.schematic', -11 )
|
||||||
|
or string.find( path, '.we', -3 )
|
||||||
|
or string.find( path, '.wem', -4 ) )) then
|
||||||
|
return ie_io_open( path, params );
|
||||||
|
elseif( (params=='w' or params=='wb')
|
||||||
|
and ( string.find( path, '.mts', -4 )
|
||||||
|
or string.find( path, '.schematic', -11 )
|
||||||
|
or string.find( path, '.we', -3 )
|
||||||
|
or string.find( path, '.wem', -4 ) )) then
|
||||||
|
return ie_io_open( path, params );
|
||||||
|
end
|
||||||
|
end
|
After Width: | Height: | Size: 261 B |
@ -0,0 +1,402 @@
|
|||||||
|
|
||||||
|
-- based on:
|
||||||
|
-- # Minecraft to Minetest WE schematic MCEdit filter
|
||||||
|
-- # by sfan5
|
||||||
|
|
||||||
|
-- #blockdata -1 means ignore
|
||||||
|
local P2_IGNORE = -1;
|
||||||
|
-- #blockdata -2 means copy without change
|
||||||
|
local P2_COPY = -2;
|
||||||
|
-- #blockdata -3 means copy and convert the mc facedir value to mt facedir
|
||||||
|
local P2_CONVERT= -3;
|
||||||
|
-- #blockdata -4 is for stairs to support upside down ones
|
||||||
|
local P2_STAIR = -4;
|
||||||
|
-- #blockdata selects one of the listed subtypes
|
||||||
|
local P2_SELECT = -5;
|
||||||
|
|
||||||
|
-- #Reference MC: http://media-mcw.cursecdn.com/8/8c/DataValuesBeta.png
|
||||||
|
-- #Reference MT:
|
||||||
|
-- # https://github.com/minetest/common/blob/master/mods/default/init.lua
|
||||||
|
-- # https://github.com/minetest/common/blob/master/mods/wool/init.lua
|
||||||
|
-- # https://github.com/minetest/common/blob/master/mods/stairs/init.lua
|
||||||
|
local conversionTable = {
|
||||||
|
-- #blockid blockdata minetest-nodename
|
||||||
|
|
||||||
|
-- [0] = {P2_IGNORE, "air"},
|
||||||
|
[1] = {P2_IGNORE, "default:stone"},
|
||||||
|
-- 0: stone; 1: granite; 2: polished granite;
|
||||||
|
-- 3: diorite; 4: polished diorite; 5: andesite;
|
||||||
|
-- 6: polished andesite
|
||||||
|
[2] = {P2_IGNORE, "default:dirt_with_grass"},
|
||||||
|
[3] = {P2_IGNORE, "default:dirt"},
|
||||||
|
-- 0: dirt; 1: coarse dirt; 2: podzol
|
||||||
|
[4] = {P2_IGNORE, "default:cobble"},
|
||||||
|
[5] = {P2_SELECT, { [0]="default:wood",
|
||||||
|
[1]="moretrees:spruce_planks",
|
||||||
|
[2]="moretrees:birch_planks",
|
||||||
|
[3]="default:junglewood",
|
||||||
|
[4]="moretrees:acacia_planks",
|
||||||
|
[5]="moretrees:oak_planks"}},
|
||||||
|
[6] = {P2_SELECT, { [0]="default:wood",
|
||||||
|
[1]="moretrees:spruce_sapling",
|
||||||
|
[2]="moretrees:birch_sapling",
|
||||||
|
[3]="default:junglesapling",
|
||||||
|
[4]="moretrees:acacia_sapling",
|
||||||
|
[5]="moretrees:oak_sapling"}},
|
||||||
|
[7] = {P2_IGNORE, "minecraft:bedrock"}, --# FIXME Bedrock
|
||||||
|
[8] = {P2_IGNORE, "default:water_flowing"},
|
||||||
|
[9] = {P2_IGNORE, "default:water_source"},
|
||||||
|
[10] = {P2_IGNORE, "default:lava_flowing"},
|
||||||
|
[11] = {P2_IGNORE, "default:lava_source"},
|
||||||
|
[12] = {P2_SELECT, { [0]="default:sand",
|
||||||
|
[1]="default:desert_sand"}},
|
||||||
|
[13] = {P2_IGNORE, "default:gravel"},
|
||||||
|
[14] = {P2_IGNORE, "default:stone_with_gold"},
|
||||||
|
[15] = {P2_IGNORE, "default:stone_with_iron"},
|
||||||
|
[16] = {P2_IGNORE, "default:stone_with_coal"},
|
||||||
|
-- TODO: the trees have facedir
|
||||||
|
[17] = {P2_SELECT, { [0]="default:tree",
|
||||||
|
[1]="moretrees:spruce_trunk",
|
||||||
|
[2]="moretrees:birch_trunk",
|
||||||
|
[3]="default:jungletree",
|
||||||
|
[4]="moretrees:acacia_trunk",
|
||||||
|
[5]="moretrees:oak_trunk"}},
|
||||||
|
[18] = {P2_SELECT, { [0]="default:leaves",
|
||||||
|
[1]="moretrees:spruce_leaves",
|
||||||
|
[2]="moretrees:birch_leaves",
|
||||||
|
[3]="default:jungleleaves",
|
||||||
|
[4]="default:leaves",
|
||||||
|
[5]="moretrees:spruce_leaves",
|
||||||
|
[6]="moretrees:birch_leaves",
|
||||||
|
[7]="default:jungleleaves",
|
||||||
|
[8]="default:leaves",
|
||||||
|
[9]="moretrees:spruce_leaves",
|
||||||
|
[10]="moretrees:birch_leaves",
|
||||||
|
[11]="default:jungleleaves",
|
||||||
|
[12]="default:leaves",
|
||||||
|
[13]="moretrees:spruce_leaves",
|
||||||
|
[14]="moretrees:birch_leaves",
|
||||||
|
[15]="default:jungleleaves"}},
|
||||||
|
[19] = {P2_CONVERT,"minecraft:sponge"},
|
||||||
|
[20] = {P2_IGNORE, "default:glass"},
|
||||||
|
[21] = {P2_IGNORE, "default:stone_with_copper"}, -- Lapis Lazuli Ore
|
||||||
|
[22] = {P2_IGNORE, "default:copperblock"}, -- Lapis Lazuli Block
|
||||||
|
[23] = {P2_CONVERT,"minecraft:dispenser"},
|
||||||
|
[24] = {P2_SELECT, { [0]="default:sandstone",
|
||||||
|
[1]="default:sandstonebrick",
|
||||||
|
[2]="default:sandstone"}},
|
||||||
|
[25] = {P2_CONVERT,"minecraft:nodeblock"},
|
||||||
|
[26] = {P2_CONVERT,"beds:bed"}, -- TODO: might require special handling?
|
||||||
|
[27] = {P2_CONVERT,"minecraft:golden_rail"},
|
||||||
|
[28] = {P2_CONVERT,"minecraft:detector_rail"},
|
||||||
|
-- 29: sticky piston
|
||||||
|
[30] = {P2_CONVERT,"minecraft:web"},
|
||||||
|
[31] = {P2_SELECT, { [0]="default:dry_shrub",
|
||||||
|
[1]="default:grass_4",
|
||||||
|
[2]="ferns:fern_02"}},
|
||||||
|
[32] = {P2_IGNORE, "default:dry_shrub"},
|
||||||
|
-- 34: piston head
|
||||||
|
[35] = {P2_SELECT, { [0]="wool:white",
|
||||||
|
[1]="wool:orange",
|
||||||
|
[2]="wool:magenta",
|
||||||
|
[3]="wool:light_blue",
|
||||||
|
[4]="wool:yellow",
|
||||||
|
[5]="wool:green",
|
||||||
|
[6]="wool:pink",
|
||||||
|
[7]="wool:dark_grey",
|
||||||
|
[8]="wool:grey",
|
||||||
|
[9]="wool:cyan",
|
||||||
|
[10]="wool:violet",
|
||||||
|
[11]="wool:blue",
|
||||||
|
[12]="wool:brown",
|
||||||
|
[13]="wool:dark_green",
|
||||||
|
[14]="wool:red",
|
||||||
|
[15]="wool:black"}},
|
||||||
|
-- 36: piston extension
|
||||||
|
[37] = {P2_IGNORE, "flowers:dandelion_yellow"},
|
||||||
|
[38] = {P2_SELECT, { [0]="flowers:rose",
|
||||||
|
[1]="flowers:geranium",
|
||||||
|
[2]="flowers:viola",
|
||||||
|
[3]="flowers:dandelion_white",
|
||||||
|
[4]="tulips:red",
|
||||||
|
[5]="flowers:tulip",
|
||||||
|
[6]="tulips:white",
|
||||||
|
[7]="tulips:pink",
|
||||||
|
[8]="tulips:black"}},
|
||||||
|
[41] = {P2_IGNORE, "default:goldblock"},
|
||||||
|
[42] = {P2_IGNORE, "default:steelblock"},
|
||||||
|
-- double stone slabs...full blocks?
|
||||||
|
[43] = {P2_SELECT, { [0]="default:stone",
|
||||||
|
[1]="default:sandstonebrick",
|
||||||
|
[2]="default:wood",
|
||||||
|
[3]="default:cobble",
|
||||||
|
[4]="default:brick",
|
||||||
|
[5]="default:stonebrick",
|
||||||
|
[6]="nether:brick",
|
||||||
|
[7]="quartz:quartz",
|
||||||
|
[8]="moreblocks:split_stone_tile",
|
||||||
|
[9]="default:sandstone"}},
|
||||||
|
[44] = {P2_SELECT, { [0]="stairs:slab_stone",
|
||||||
|
[1]="stairs:slab_sandstone",
|
||||||
|
[2]="stairs:slab_wood",
|
||||||
|
[3]="stairs:slab_cobble",
|
||||||
|
[4]="stairs:slab_brick",
|
||||||
|
[5]="stairs:slab_stonebrick",
|
||||||
|
[6]="stairs:slab_nether",
|
||||||
|
[7]="stairs:slab_quartz",
|
||||||
|
[8]="stairs:slab_stoneupside_down",
|
||||||
|
[9]="stairs:slab_sandstoneupside_down",
|
||||||
|
[10]="stairs:slab_woodupside_down",
|
||||||
|
[11]="stairs:slab_cobbleupside_down",
|
||||||
|
[12]="stairs:slab_brickupside_down",
|
||||||
|
[13]="stairs:slab_stonebrickupside_down",
|
||||||
|
[14]="stairs:slab_netzerupside_down",
|
||||||
|
[15]="stairs:slab_quartzupside_down"}},
|
||||||
|
[45] = {P2_IGNORE, "default:brick"},
|
||||||
|
[46] = {P2_CONVERT,"tnt:tnt"},
|
||||||
|
[47] = {P2_IGNORE, "default:bookshelf"},
|
||||||
|
[48] = {P2_IGNORE, "default:mossycobble"},
|
||||||
|
[49] = {P2_IGNORE, "default:obsidian"},
|
||||||
|
[50] = {P2_CONVERT,"default:torch"},
|
||||||
|
[51] = {P2_IGNORE, "fire:basic_flame"},
|
||||||
|
[52] = {P2_CONVERT,"minecraft:mob_spawner"},
|
||||||
|
[53] = {P2_STAIR, "stairs:stair_wood"},
|
||||||
|
[54] = {P2_IGNORE, "default:chest"},
|
||||||
|
[56] = {P2_IGNORE, "default:stone_with_diamond"},
|
||||||
|
[57] = {P2_IGNORE, "default:diamondblock"},
|
||||||
|
[58] = {P2_CONVERT,"minecraft:crafting_table"},
|
||||||
|
[59] = {P2_IGNORE, "farming:wheat_8"},
|
||||||
|
[60] = {P2_IGNORE, "farming:soil_wet"},
|
||||||
|
[61] = {P2_IGNORE, "default:furnace"},
|
||||||
|
[62] = {P2_IGNORE, "default:furnace_active"},
|
||||||
|
[63] = {P2_IGNORE, "default:sign_wall"},
|
||||||
|
[64] = {P2_IGNORE, "doors:door_wood_t_1"},
|
||||||
|
[65] = {P2_IGNORE, "default:ladder"},
|
||||||
|
[66] = {P2_IGNORE, "default:rail"},
|
||||||
|
[67] = {P2_STAIR, "stairs:stair_cobble"},
|
||||||
|
[68] = {P2_CONVERT,"default:sign_wall"},
|
||||||
|
[71] = {P2_IGNORE, "doors:door_steel_t_1"},
|
||||||
|
[78] = {P2_IGNORE, "default:snow"},
|
||||||
|
[79] = {P2_IGNORE, "default:ice"},
|
||||||
|
[80] = {P2_IGNORE, "default:snowblock"},
|
||||||
|
[81] = {P2_IGNORE, "default:cactus"},
|
||||||
|
[82] = {P2_IGNORE, "default:clay"},
|
||||||
|
[83] = {P2_IGNORE, "default:papyrus"},
|
||||||
|
[84] = {P2_CONVERT,"minecraft:jukebox"},
|
||||||
|
[85] = {P2_IGNORE, "default:fence_wood"},
|
||||||
|
[86] = {P2_CONVERT,"farming:pumpkin"},
|
||||||
|
[91] = {P2_CONVERT,"farming:pumpkin_face_light"},
|
||||||
|
[92] = {P2_CONVERT,"minecraft:cake"},
|
||||||
|
[95] = {P2_IGNORE, "minecraft:stained_glass"}, -- TODO
|
||||||
|
[96] = {P2_CONVERT,"doors:trapdoor"},
|
||||||
|
[97] = {P2_IGNORE, "minecraft:monster_egg"},
|
||||||
|
[98] = {P2_IGNORE, "default:stonebrick"},
|
||||||
|
[108]= {P2_STAIR, "stairs:stair_brick"},
|
||||||
|
[109]= {P2_CONVERT,"stairs:stair_stonebrick"},
|
||||||
|
-- TODO: double ... wood slab...
|
||||||
|
[125]= {P2_SELECT, { [0]="default:wood",
|
||||||
|
[1]="moretrees:spruce_planks",
|
||||||
|
[2]="moretrees:birch_planks",
|
||||||
|
[3]="default:junglewood",
|
||||||
|
[4]="moretrees:acacia_planks",
|
||||||
|
[5]="moretrees:oak_planks"}},
|
||||||
|
[125]= {P2_IGNORE, "default:wood"},
|
||||||
|
[126]= {P2_SELECT, { [0]="stairs:slab_wood",
|
||||||
|
[1]="stairs:slab_spruce_planks",
|
||||||
|
[2]="stairs:slab_birch_planks",
|
||||||
|
[3]="stairs:slab_junglewood",
|
||||||
|
[4]="stairs:slab_acacia_planks",
|
||||||
|
[5]="stairs:slab_oak_planks",
|
||||||
|
[8]="stairs:slab_woodupside_down",
|
||||||
|
[9]="stairs:slab_spruce_planksupside_down",
|
||||||
|
[10]="stairs:slab_birch_planksupside_down",
|
||||||
|
[11]="stairs:slab_junglewoodupside_down",
|
||||||
|
[12]="stairs:slab_acacia_planksupside_down",
|
||||||
|
[13]="stairs:slab_oak_planksupside_down"}},
|
||||||
|
[126]= {P2_IGNORE, "stairs:slab_wood"},
|
||||||
|
[128]= {P2_STAIR, "stairs:stair_sandstone"},
|
||||||
|
[129]= {P2_IGNORE, "default:stone_with_mese"},
|
||||||
|
[133]= {P2_IGNORE, "default:mese"},
|
||||||
|
[134]= {P2_STAIR, "stairs:stair_wood"},
|
||||||
|
[135]= {P2_STAIR, "stairs:stair_wood"},
|
||||||
|
[136]= {P2_STAIR, "stairs:stair_junglewood"},
|
||||||
|
|
||||||
|
-- #Mesecons section
|
||||||
|
-- # Reference: https://github.com/Jeija/minetest-mod-mesecons/blob/master/mesecons_alias/init.lua
|
||||||
|
[25] = {P2_IGNORE, "mesecons_noteblock:noteblock"},
|
||||||
|
[29] = {P2_CONVERT,"mesecons_pistons:piston_sticky_off"},
|
||||||
|
[33] = {P2_CONVERT,"mesecons_pistons:piston_normal_off"},
|
||||||
|
[55] = {P2_IGNORE, "mesecons:wire_00000000_off"},
|
||||||
|
[69] = {P2_CONVERT,"mesecons_walllever:wall_lever_off"},
|
||||||
|
[70] = {P2_IGNORE, "mesecons_pressureplates:pressure_plate_stone_off"},
|
||||||
|
[72] = {P2_IGNORE, "mesecons_pressureplates:pressure_plate_wood_off"},
|
||||||
|
[73] = {P2_IGNORE, "default:stone_with_mese"},
|
||||||
|
[74] = {P2_IGNORE, "default:stone_with_mese"},
|
||||||
|
[75] = {P2_CONVERT,"mesecons_torch:torch_off"},
|
||||||
|
[76] = {P2_CONVERT,"mesecons_torch:torch_on"},
|
||||||
|
[77] = {P2_CONVERT,"mesecons_button:button_off"},
|
||||||
|
[93] = {P2_CONVERT,"mesecons_delayer:delayer_off_1"},
|
||||||
|
[94] = {P2_CONVERT,"mesecons_delayer:delayer_on_1"},
|
||||||
|
-- see mod https://github.com/doyousketch2/stained_glass
|
||||||
|
[95] = {P2_SELECT, { [0]="default:glass", -- TODO
|
||||||
|
[1]="stained_glass:orange__",
|
||||||
|
[2]="stained_glass:magenta__",
|
||||||
|
[3]="stained_glass:skyblue__",
|
||||||
|
[4]="stained_glass:yellow__",
|
||||||
|
[5]="stained_glass:lime__",
|
||||||
|
[6]="stained_glass:redviolet__",
|
||||||
|
[7]="stained_glass:dark_grey__", -- TODO
|
||||||
|
[8]="stained_glass:grey__", -- TODO
|
||||||
|
[9]="stained_glass:cyan__",
|
||||||
|
[10]="stained_glass:violet__",
|
||||||
|
[11]="stained_glass:blue__",
|
||||||
|
[12]="stained_glass:orange_dark_",
|
||||||
|
[13]="stained_glass:green__",
|
||||||
|
[14]="stained_glass:red__",
|
||||||
|
[15]="stained_glass:black__"}}, -- TODO
|
||||||
|
[101]= {P2_CONVERT,"xpanes:bar"},
|
||||||
|
[102]= {P2_CONVERT,"xpanes:pane"},
|
||||||
|
[103]= {P2_IGNORE, "farming:melon"},
|
||||||
|
[104]= {P2_IGNORE, "minecraft:pumpkin_stem"},
|
||||||
|
[105]= {P2_IGNORE, "minecraft:melon_stem"},
|
||||||
|
[106]= {P2_CONVERT,"vines:vine"},
|
||||||
|
[107]= {P2_CONVERT,"minecraft:fence_gate"},
|
||||||
|
[108]= {P2_STAIR, "stairs:stair_brick"},
|
||||||
|
[109]= {P2_STAIR, "stairs:stair_stonebrick"},
|
||||||
|
[110]= {P2_CONVERT,"minecraft:mycelium"},
|
||||||
|
[111]= {P2_CONVERT,"flowers:waterlily"},
|
||||||
|
[112]= {P2_CONVERT,"minecraft:nether_brick"},
|
||||||
|
[113]= {P2_CONVERT,"minecraft:nether_brick_fence"},
|
||||||
|
[114]= {P2_CONVERT,"minecraft:nether_brick_stairs"},
|
||||||
|
[115]= {P2_CONVERT,"minecraft:nether_wart"},
|
||||||
|
[116]= {P2_CONVERT,"minecraft:enchanting_table"},
|
||||||
|
[117]= {P2_CONVERT,"minecraft:brewing_stand"},
|
||||||
|
[118]= {P2_CONVERT,"minecraft:cauldron"},
|
||||||
|
[119]= {P2_CONVERT,"minecraft:end_portal"},
|
||||||
|
[120]= {P2_CONVERT,"minecraft:end_portal_frame"},
|
||||||
|
[121]= {P2_CONVERT,"minecraft:end_stone"},
|
||||||
|
[122]= {P2_CONVERT,"minecraft:dragon_egg"},
|
||||||
|
[123]= {P2_IGNORE, "mesecons_lightstone_red_off"},
|
||||||
|
[124]= {P2_IGNORE, "mesecons_lightstone_red_on"},
|
||||||
|
[125]= {P2_CONVERT,"minecraft:double_wooden_slab"},
|
||||||
|
[126]= {P2_CONVERT,"stairs:slab_wood"},
|
||||||
|
[127]= {P2_CONVERT,"farming_plus:cocoa"},
|
||||||
|
[137]= {P2_IGNORE, "mesecons_commandblock:commandblock_off"},
|
||||||
|
[151]= {P2_IGNORE, "mesecons_solarpanel:solar_panel_off"},
|
||||||
|
[152]= {P2_IGNORE, "default:mese"},
|
||||||
|
-- see mod https://github.com/tenplus1/bakedclay
|
||||||
|
[159] = {P2_SELECT, { [0]="bakedclay:white",
|
||||||
|
[1]="bakedclay:orange",
|
||||||
|
[2]="bakedclay:magenta",
|
||||||
|
[3]="bakedclay:light_blue", -- TODO
|
||||||
|
[4]="bakedclay:yellow",
|
||||||
|
[5]="bakedclay:green",
|
||||||
|
[6]="bakedclay:pink",
|
||||||
|
[7]="bakedclay:dark_grey",
|
||||||
|
[8]="bakedclay:grey",
|
||||||
|
[9]="bakedclay:cyan",
|
||||||
|
[10]="bakedclay:violet",
|
||||||
|
[11]="bakedclay:blue",
|
||||||
|
[12]="bakedclay:brown",
|
||||||
|
[13]="bakedclay:dark_green",
|
||||||
|
[14]="bakedclay:red",
|
||||||
|
[15]="bakedclay:black"}},
|
||||||
|
-- see mod mccarpet https://forum.minetest.net/viewtopic.php?t=7419
|
||||||
|
[171] = {P2_SELECT, { [0]="mccarpet:white",
|
||||||
|
[1]="mccarpet:orange",
|
||||||
|
[2]="mccarpet:magenta",
|
||||||
|
[3]="mccarpet:light_blue", -- TODO
|
||||||
|
[4]="mccarpet:yellow",
|
||||||
|
[5]="mccarpet:green",
|
||||||
|
[6]="mccarpet:pink",
|
||||||
|
[7]="mccarpet:dark_grey",
|
||||||
|
[8]="mccarpet:grey",
|
||||||
|
[9]="mccarpet:cyan",
|
||||||
|
[10]="mccarpet:violet",
|
||||||
|
[11]="mccarpet:blue",
|
||||||
|
[12]="mccarpet:brown",
|
||||||
|
[13]="mccarpet:dark_green",
|
||||||
|
[14]="mccarpet:red",
|
||||||
|
[15]="mccarpet:black"}},
|
||||||
|
[181] = {P2_SELECT, { [0]="default:desert_stonebrick",
|
||||||
|
[1]="default:desertstone"}},
|
||||||
|
|
||||||
|
-- #Nether section
|
||||||
|
-- # Reference: https://github.com/PilzAdam/nether/blob/master/init.lua
|
||||||
|
[43] = {P2_IGNORE, "nether:brick"},
|
||||||
|
[87] = {P2_IGNORE, "nether:rack"},
|
||||||
|
[88] = {P2_IGNORE, "nether:sand"},
|
||||||
|
[89] = {P2_IGNORE, "nether:glowstone"},
|
||||||
|
[90] = {P2_CONVERT,"nether:portal"},
|
||||||
|
|
||||||
|
-- #Riesenpilz Section
|
||||||
|
-- # Reference: https://github.com/HybridDog/riesenpilz/blob/master/init.lua
|
||||||
|
[39] = {P2_IGNORE, "riesenpilz:brown"},
|
||||||
|
[40] = {P2_IGNORE, "riesenpilz:red"},
|
||||||
|
[99] = {P2_CONVERT,"riesenpilz:head_brown"},
|
||||||
|
[100]= {P2_CONVERT,"riesenpilz:head_brown"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local mc2mtFacedir = function(blockdata)
|
||||||
|
-- #Minetest
|
||||||
|
-- # x+ = 2
|
||||||
|
-- # x- = 3
|
||||||
|
-- # z+ = 1
|
||||||
|
-- # z- = 0
|
||||||
|
-- #Minecraft
|
||||||
|
-- # x+ = 3
|
||||||
|
-- # x- = 1
|
||||||
|
-- # z+ = 0
|
||||||
|
-- # z- = 2
|
||||||
|
local tbl = {
|
||||||
|
[3]= 2,
|
||||||
|
[1]= 1,
|
||||||
|
[0]= 3,
|
||||||
|
[2]= 0,
|
||||||
|
}
|
||||||
|
if( tbl[ blockdata ] ) then
|
||||||
|
return tbl[ blockdata ];
|
||||||
|
-- this happens with i.e. wallmounted torches...
|
||||||
|
else
|
||||||
|
return blockdata;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local mc2mtstairs = function( name, blockdata)
|
||||||
|
if blockdata >= 4 then
|
||||||
|
return {name.. "upside_down", mc2mtFacedir(blockdata - 4)}
|
||||||
|
else
|
||||||
|
return {name, mc2mtFacedir(blockdata)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- returns {translated_node_name, translated_param2}
|
||||||
|
handle_schematics.findMC2MTConversion = function(blockid, blockdata)
|
||||||
|
if (blockid == 0 ) then
|
||||||
|
return {"air",0};
|
||||||
|
-- fallback
|
||||||
|
elseif( not( conversionTable[ blockid ])) then
|
||||||
|
return { "minecraft:"..tostring( blockid )..'_'..tostring( blockdata ), 0};
|
||||||
|
end
|
||||||
|
local conv = conversionTable[ blockid ];
|
||||||
|
if( conv[1] == P2_IGNORE ) then
|
||||||
|
return { conv[2], 0};
|
||||||
|
elseif( conv[1] == P2_COPY ) then
|
||||||
|
return { conv[2], blockdata};
|
||||||
|
elseif( conv[1] == P2_CONVERT) then
|
||||||
|
return { conv[2], mc2mtFacedir(blockdata)};
|
||||||
|
elseif( conv[1] == P2_STAIR ) then
|
||||||
|
return mc2mtstairs(conv[2], blockdata);
|
||||||
|
elseif( conv[1] == P2_SELECT
|
||||||
|
and conv[2][ blockdata ] ) then
|
||||||
|
return { conv[2][ blockdata ], 0};
|
||||||
|
elseif( conv[1] == P2_SELECT
|
||||||
|
and not(conv[2][ blockdata ] )) then
|
||||||
|
return { conv[2][0], 0};
|
||||||
|
else
|
||||||
|
return { conv[2], 0 };
|
||||||
|
end
|
||||||
|
return {air, 0};
|
||||||
|
end
|
138
mods/a_mapgen_mods/handle_schematics/worldedit_file.lua
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
------------------------------------------------------------------------------------------
|
||||||
|
-- This is the file
|
||||||
|
-- https://github.com/Uberi/Minetest-WorldEdit/blob/master/worldedit/serialization.lua
|
||||||
|
-- Changes:
|
||||||
|
-- * worldedit namespace renamed to worldeit_file
|
||||||
|
-- * eliminiated functions that are not needed
|
||||||
|
-- * made function load_schematic non-local
|
||||||
|
-- * originx, originy and originz are now passed as parameters to worldedit_file.load_schematic;
|
||||||
|
-- they are required for an old file format
|
||||||
|
------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
worldedit_file = {} -- add the namespace
|
||||||
|
|
||||||
|
--- Schematic serialization and deserialiation.
|
||||||
|
-- @module worldedit.serialization
|
||||||
|
|
||||||
|
worldedit_file.LATEST_SERIALIZATION_VERSION = 5
|
||||||
|
local LATEST_SERIALIZATION_HEADER = worldedit_file.LATEST_SERIALIZATION_VERSION .. ":"
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Serialization version history:
|
||||||
|
1: Original format. Serialized Lua table with a weird linked format...
|
||||||
|
2: Position and node seperated into sub-tables in fields `1` and `2`.
|
||||||
|
3: List of nodes, one per line, with fields seperated by spaces.
|
||||||
|
Format: <X> <Y> <Z> <Name> <Param1> <Param2>
|
||||||
|
4: Serialized Lua table containing a list of nodes with `x`, `y`, `z`,
|
||||||
|
`name`, `param1`, `param2`, and `meta` fields.
|
||||||
|
5: Added header and made `param1`, `param2`, and `meta` fields optional.
|
||||||
|
Header format: <Version>,<ExtraHeaderField1>,...:<Content>
|
||||||
|
--]]
|
||||||
|
|
||||||
|
|
||||||
|
--- Reads the header of serialized data.
|
||||||
|
-- @param value Serialized WorldEdit data.
|
||||||
|
-- @return The version as a positive natural number, or 0 for unknown versions.
|
||||||
|
-- @return Extra header fields as a list of strings, or nil if not supported.
|
||||||
|
-- @return Content (data after header).
|
||||||
|
function worldedit_file.read_header(value)
|
||||||
|
if value:find("^[0-9]+[%-:]") then
|
||||||
|
local header_end = value:find(":", 1, true)
|
||||||
|
local header = value:sub(1, header_end - 1):split(",")
|
||||||
|
local version = tonumber(header[1])
|
||||||
|
table.remove(header, 1)
|
||||||
|
local content = value:sub(header_end + 1)
|
||||||
|
return version, header, content
|
||||||
|
end
|
||||||
|
-- Old versions that didn't include a header with a version number
|
||||||
|
if value:find("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)") and not value:find("%{") then -- List format
|
||||||
|
return 3, nil, value
|
||||||
|
elseif value:find("^[^\"']+%{%d+%}") then
|
||||||
|
if value:find("%[\"meta\"%]") then -- Meta flat table format
|
||||||
|
return 2, nil, value
|
||||||
|
end
|
||||||
|
return 1, nil, value -- Flat table format
|
||||||
|
elseif value:find("%{") then -- Raw nested table format
|
||||||
|
return 4, nil, value
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Loads the schematic in `value` into a node list in the latest format.
|
||||||
|
-- Contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile)
|
||||||
|
-- by ChillCode, available under the MIT license.
|
||||||
|
-- @return A node list in the latest format, or nil on failure.
|
||||||
|
function worldedit_file.load_schematic(value, we_origin)
|
||||||
|
local version, header, content = worldedit_file.read_header(value)
|
||||||
|
local nodes = {}
|
||||||
|
if version == 1 or version == 2 then -- Original flat table format
|
||||||
|
local tables = minetest.deserialize(content)
|
||||||
|
if not tables then return nil end
|
||||||
|
|
||||||
|
-- Transform the node table into an array of nodes
|
||||||
|
for i = 1, #tables do
|
||||||
|
for j, v in pairs(tables[i]) do
|
||||||
|
if type(v) == "table" then
|
||||||
|
tables[i][j] = tables[v[1]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nodes = tables[1]
|
||||||
|
|
||||||
|
if version == 1 then --original flat table format
|
||||||
|
for i, entry in ipairs(nodes) do
|
||||||
|
local pos = entry[1]
|
||||||
|
entry.x, entry.y, entry.z = pos.x, pos.y, pos.z
|
||||||
|
entry[1] = nil
|
||||||
|
local node = entry[2]
|
||||||
|
entry.name, entry.param1, entry.param2 = node.name, node.param1, node.param2
|
||||||
|
entry[2] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif version == 3 or version=="3" then -- List format
|
||||||
|
if( not( we_origin ) or #we_origin <3) then
|
||||||
|
we_origin = { 0, 0, 0 };
|
||||||
|
end
|
||||||
|
for x, y, z, name, param1, param2 in content:gmatch(
|
||||||
|
"([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+" ..
|
||||||
|
"([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do
|
||||||
|
param1, param2 = tonumber(param1), tonumber(param2)
|
||||||
|
table.insert(nodes, {
|
||||||
|
x = we_origin[1] + tonumber(x),
|
||||||
|
y = we_origin[2] + tonumber(y),
|
||||||
|
z = we_origin[3] + tonumber(z),
|
||||||
|
name = name,
|
||||||
|
param1 = param1 ~= 0 and param1 or nil,
|
||||||
|
param2 = param2 ~= 0 and param2 or nil,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
elseif version == 4 or version == 5 then -- Nested table format
|
||||||
|
if not jit then
|
||||||
|
-- This is broken for larger tables in the current version of LuaJIT
|
||||||
|
nodes = minetest.deserialize(content)
|
||||||
|
else
|
||||||
|
-- XXX: This is a filthy hack that works surprisingly well - in LuaJIT, `minetest.deserialize` will fail due to the register limit
|
||||||
|
nodes = {}
|
||||||
|
content = content:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1) -- remove the starting and ending values to leave only the node data
|
||||||
|
local escaped = content:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end)
|
||||||
|
local startpos, startpos1, endpos = 1, 1
|
||||||
|
while true do -- go through each individual node entry (except the last)
|
||||||
|
startpos, endpos = escaped:find("},%s*{", startpos)
|
||||||
|
if not startpos then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local current = content:sub(startpos1, startpos)
|
||||||
|
local entry = minetest.deserialize("return " .. current)
|
||||||
|
table.insert(nodes, entry)
|
||||||
|
startpos, startpos1 = endpos, endpos
|
||||||
|
end
|
||||||
|
local entry = minetest.deserialize("return " .. content:sub(startpos1)) -- process the last entry
|
||||||
|
table.insert(nodes, entry)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return nodes
|
||||||
|
end
|
187
mods/a_mapgen_mods/mg_villages/--config -orig.lua
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- configuration values which you can adjust according to your liking
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- set to false if you do not want to have any villages spawning
|
||||||
|
mg_villages.ENABLE_VILLAGES = true;
|
||||||
|
|
||||||
|
-- generate one random building for each mg_villages.INVERSE_HOUSE_DENSITY th mapchunk;
|
||||||
|
-- set to 0 in order to disable spawning of these lone buildings outside villages
|
||||||
|
mg_villages.INVERSE_HOUSE_DENSITY = 4;
|
||||||
|
|
||||||
|
-- cover some villages with artificial snow; probability: 1/mg_villages.artificial_snow_probability
|
||||||
|
mg_villages.artificial_snow_probability = 10;
|
||||||
|
|
||||||
|
-- if set to true, soil around villaes will get special soil-snow instead of plant + snow cover
|
||||||
|
mg_villages.use_soil_snow = false;
|
||||||
|
|
||||||
|
-- only place roads if there are at least that many buildings in the village
|
||||||
|
mg_villages.MINIMAL_BUILDUNGS_FOR_ROAD_PLACEMENT = 4;
|
||||||
|
|
||||||
|
|
||||||
|
-- players without the mg_villages priv can only see villages which are less than that many blocks away
|
||||||
|
-- from them when using the /vmap command
|
||||||
|
mg_villages.VILLAGE_DETECT_RANGE = 400;
|
||||||
|
|
||||||
|
-- if set to true, only players which have the mg_villages priv can use the "/visit <village nr>"
|
||||||
|
-- command which allows teleporting to the village with the given number
|
||||||
|
mg_villages.REQUIRE_PRIV_FOR_TELEPORT = false;
|
||||||
|
|
||||||
|
-- if set to true, players cannot modify spawned villages without buying the house from the village first
|
||||||
|
mg_villages.ENABLE_PROTECTION = true;
|
||||||
|
|
||||||
|
-- the first village - the one the player spawns in - will be of this type
|
||||||
|
mg_villages.FIRST_VILLAGE_TYPE = 'medieval';
|
||||||
|
|
||||||
|
-- the mapgen will disregard mapchunks where min.y > mg_villages.MAX_HEIGHT_TREATED;
|
||||||
|
-- you can set this value to 64 if you have a slow machine and a mapgen which does not create extreme mountains
|
||||||
|
-- (or if you don't care if extreme mountains may create burried villages occasionally)
|
||||||
|
mg_villages.MAX_HEIGHT_TREATED = 200;
|
||||||
|
|
||||||
|
-- choose the debug level you want
|
||||||
|
mg_villages.DEBUG_LEVEL = mg_villages.DEBUG_LEVEL_NORMAL
|
||||||
|
|
||||||
|
-- if set to true (or anything else but nil or false), highlandpools by paramat (see
|
||||||
|
-- https://forum.minetest.net/viewtopic.php?t=8400) will be created
|
||||||
|
mg_villages.CREATE_HIGHLANDPOOLS = true
|
||||||
|
|
||||||
|
-- background image for the /vmap command
|
||||||
|
-- RealTest comes with a diffrent texture
|
||||||
|
if( minetest.get_modpath('grounds') and minetest.get_modpath('joiner_table')) then
|
||||||
|
mg_villages.MAP_BACKGROUND_IMAGE = "default_dirt_grass.png";
|
||||||
|
elseif( minetest.registered_nodes[ 'default:dirt_with_grass'] ) then
|
||||||
|
mg_villages.MAP_BACKGROUND_IMAGE = "default_grass.png";
|
||||||
|
else
|
||||||
|
mg_villages.MAP_BACKGROUND_IMAGE = "";
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if set to true, the outer buildings in medieval villages will be fields; this is not very convincing yet
|
||||||
|
-- currently not really used; does not look as good as expected
|
||||||
|
mg_villages.medieval_subtype = false;
|
||||||
|
|
||||||
|
-- set this to true if you want to use normal lava - but beware: charachoal villages may cause bushfires!
|
||||||
|
--mg_villages.use_normal_unsafe_lava = false;
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- decrese these values slightly if you want MORE trees around your villages;
|
||||||
|
-- increase it if you want to DECREASE the amount of trees around villages
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- on average, every n.th node inside a village area may be one of these trees - and it will be a relatively dense packed forrest
|
||||||
|
mg_villages.sapling_probability = {};
|
||||||
|
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'default:sapling' ) ] = 25; -- suitable for a relatively dense forrest of normal trees
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'default:junglesapling' ) ] = 40; -- jungletrees are a bit bigger and need more space
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'default:pinesapling' ) ] = 30;
|
||||||
|
if( minetest.get_modpath( 'mg' )) then
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'mg:savannasapling' ) ] = 30;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'mg:pinesapling' ) ] = 35;
|
||||||
|
end
|
||||||
|
mg_villages.moretrees_treelist = nil;
|
||||||
|
if( minetest.get_modpath( 'moretrees' )) then
|
||||||
|
mg_villages.moretrees_treelist = moretrees.treelist;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:birch_sapling_ongen' ) ] = 200;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:spruce_sapling_ongen' ) ] = 200;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:fir_sapling_ongen' ) ] = 90;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:jungletree_sapling_ongen' ) ] = 200;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:beech_sapling_ongen' ) ] = 30;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:apple_sapling_ongen' ) ] = 380;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:oak_sapling_ongen' ) ] = 380; -- ca 20x20; height: 10
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:sequoia_sapling_ongen' ) ] = 90; -- ca 10x10
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:palm_sapling_ongen' ) ] = 90;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:pine_sapling_ongen' ) ] = 200;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:willow_sapling_ongen' ) ] = 380;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:rubber_tree_sapling_ongen' ) ] = 380;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- no need to change this, unless you add new farming_plus fruits
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- the schematics for buildings of type 'farm_tiny' grow cotton; the farming_plus fruits would be far more fitting
|
||||||
|
mg_villages.fruit_list = {'carrot','potatoe','orange','rhubarb','strawberry','tomato','cotton'};
|
||||||
|
-- is farming_plus available? If not, we can't use this
|
||||||
|
if( not( minetest.get_modpath("farming_plus"))) then
|
||||||
|
mg_villages.fruit_list = nil;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- players can buy plots in villages with houses on for this price;
|
||||||
|
-- set according to your liking
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- how much does the player have to pay for a plot with a building?
|
||||||
|
mg_villages.prices = {
|
||||||
|
empty = "default:copper_ingot 1", -- plot to build on
|
||||||
|
|
||||||
|
-- building types which usually have inhabitants (and thus allow the player
|
||||||
|
-- who bought the building to modifiy the entire village area minus other
|
||||||
|
-- buildings)
|
||||||
|
tent = "default:copper_ingot 1",
|
||||||
|
hut = "default:copper_ingot 1",
|
||||||
|
farm_full = "default:gold_ingot 4",
|
||||||
|
farm_tiny = "default:gold_ingot 2",
|
||||||
|
lumberjack = "default:gold_ingot 2",
|
||||||
|
house = "default:gold_ingot 2",
|
||||||
|
house_large = "default:gold_ingot 4",
|
||||||
|
tavern = "default:gold_ingot 12",
|
||||||
|
trader = "default:gold_ingot 2",
|
||||||
|
|
||||||
|
-- more or less community buildings
|
||||||
|
well = "default:gold_ingot 1",
|
||||||
|
village_square = "default:goldblock 1",
|
||||||
|
secular = "default:goldblock 2", -- secular buildings, such as libraries ec.
|
||||||
|
church = "default:goldblock 10",
|
||||||
|
|
||||||
|
-- places for mobs to work at; usually without inhabitants
|
||||||
|
tower = "default:copper_ingot 1",
|
||||||
|
shed = "default:copper_ingot 2",
|
||||||
|
pit = "default:copper_ingot 3", -- claytrader pit
|
||||||
|
mill = "default:gold_ingot 10",
|
||||||
|
forge = "default:gold_ingot 10",
|
||||||
|
bakery = "default:gold_ingot 10",
|
||||||
|
shop = "default:gold_ingot 20",
|
||||||
|
sawmill = "default:gold_ingot 30",
|
||||||
|
|
||||||
|
-- decoration
|
||||||
|
wagon = "default:tree 10",
|
||||||
|
bench = "default:tree 4",
|
||||||
|
|
||||||
|
-- seperate fields
|
||||||
|
pasture = "default:copper_ingot 2",
|
||||||
|
field = "default:copper_ingot 2",
|
||||||
|
|
||||||
|
-- chateaus are expensive
|
||||||
|
chateau = "default:diamondblock 5",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- The values below seldom need adjustment; don't change them unless you
|
||||||
|
-- know exactly what you are doing.
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- if set to false, villages will not be integrated into the terrain - which looks very bad
|
||||||
|
mg_villages.ENABLE_TERRAIN_BLEND = true;
|
||||||
|
-- if set to false, holes digged by cavegen and mudflow inside the village will not be repaired; houses will be destroyed
|
||||||
|
mg_villages.UNDO_CAVEGEN_AND_MUDFLOW = true;
|
||||||
|
|
||||||
|
-- internal variables for village generation
|
||||||
|
|
||||||
|
mg_villages.VILLAGE_CHECK_RADIUS = 2
|
||||||
|
mg_villages.VILLAGE_CHECK_COUNT = 1
|
||||||
|
--mg_villages.VILLAGE_CHANCE = 28
|
||||||
|
--mg_villages.VILLAGE_MIN_SIZE = 20
|
||||||
|
--mg_villages.VILLAGE_MAX_SIZE = 40
|
||||||
|
mg_villages.VILLAGE_CHANCE = 28
|
||||||
|
-- min and max size are only used in case of them beeing not provided by the village type (see buildings.lua)
|
||||||
|
mg_villages.VILLAGE_MIN_SIZE = 25
|
||||||
|
mg_villages.VILLAGE_MAX_SIZE = 90 --55
|
||||||
|
mg_villages.FIRST_ROADSIZE = 3
|
||||||
|
mg_villages.BIG_ROAD_CHANCE = 0
|
||||||
|
|
||||||
|
-- Enable that for really big villages (there are also really slow to generate)
|
||||||
|
--[[mg_villages.VILLAGE_CHECK_RADIUS = 3
|
||||||
|
mg_villages.VILLAGE_CHECK_COUNT = 3
|
||||||
|
mg_villages.VILLAGE_CHANCE = 28
|
||||||
|
mg_villages.VILLAGE_MIN_SIZE = 100
|
||||||
|
mg_villages.VILLAGE_MAX_SIZE = 150
|
||||||
|
mg_villages.FIRST_ROADSIZE = 5
|
||||||
|
mg_villages.BIG_ROAD_CHANCE = 50]]
|
3
mods/a_mapgen_mods/mg_villages/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
This is a continuation of my (Sokomines) fork of Nores mg mapgen.
|
||||||
|
The fork can be found under https://github.com/Sokomine/mg
|
||||||
|
|
430
mods/a_mapgen_mods/mg_villages/buildings.lua
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
-- scm="bla" Name of the file that holds the buildings' schematic. Supported types: .we and .mts (omit the extension!)
|
||||||
|
-- sizex, sizez, ysize: obsolete
|
||||||
|
-- yoff=0 how deep is the building burried?
|
||||||
|
-- pervillage=1 Never generate more than this amount of this building and this type (if set) of building per village.
|
||||||
|
-- axis=1 Building needs to be mirrored along the x-axis instead of the z-axis because it is initially rotated
|
||||||
|
-- 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
|
||||||
|
-- we_origin Only needed for very old .we files (savefile format version 3) which do not start at 0,0,0 but have an offset.
|
||||||
|
-- price Stack that has to be paid in order to become owner of the plot the building stands on and the building;
|
||||||
|
-- overrides mg_villages.prices[ building_typ ].
|
||||||
|
|
||||||
|
mg_villages.all_buildings_list = {}
|
||||||
|
|
||||||
|
local buildings = {
|
||||||
|
|
||||||
|
-- the houses the mod came with
|
||||||
|
{yoff= 0, scm="house", orients={2}, typ='house', weight={nore=1, single=2 }, inh=4},
|
||||||
|
{yoff= 0, scm="wheat_field", typ='field', weight={nore=1 }, inh=-1},
|
||||||
|
{yoff= 0, scm="cotton_field", typ='field', weight={nore=1 }, inh=-1},
|
||||||
|
{yoff= 1, scm="lamp", no_rotate=true, typ='deco', weight={nore=1/5 }},
|
||||||
|
{yoff=-5, scm="well", no_rotate=true, pervillage=1, typ='well', weight={nore=1 }},
|
||||||
|
{yoff= 0, scm="fountain", pervillage=3, typ='fountain', weight={nore=1/4 }, axis=1},
|
||||||
|
{yoff= 0, scm="small_house", orients={3}, typ='house', weight={nore=1, single=2 }, axis=1, inh=2},
|
||||||
|
{yoff= 0, scm="house_with_garden", orients={1}, typ='house', weight={nore=1, single=2 }, axis=1, inh=3},
|
||||||
|
{yoff= 0, scm="church", orients={3}, pervillage=1, typ='church', weight={nore=1 }, axis=1, inh=-1},
|
||||||
|
{yoff= 0, scm="tower", orients={0}, typ='tower', weight={nore=1/7, single=1 }, inh=-1},
|
||||||
|
{yoff= 0, scm="forge", orients={0}, pervillage=2, typ='forge', weight={nore=1, single=1/3 }, inh=-1},
|
||||||
|
{yoff= 0, scm="library", orients={1}, pervillage=2, typ='secular', weight={nore=1 }, axis=1, inh=-1},
|
||||||
|
{yoff= 0, scm="inn", orients={1}, pervillage=4, typ='tavern', weight={nore=1/2, single=1/3 }, axis=1, inh=-1}, -- has room for 4 guests
|
||||||
|
{yoff= 0, scm="pub", orients={3}, pervillage=2, typ='tavern', weight={nore=1/3, single=1/3 }, axis=1, inh=-1},
|
||||||
|
|
||||||
|
|
||||||
|
-- log cabins by Sokomine (requiring cottages, glasspanes)
|
||||||
|
{yoff= 0, scm="logcabin1", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=2, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin2", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=2, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin3", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=3, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin4", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=3, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin5", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=1, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin6", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=1, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin7", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=2, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin8", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=2, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin9", orients={1}, weight={logcabin=1, single=1}, axis=1, inh=1, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin10", orients={2}, weight={logcabin=1, single=1}, inh=3, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabin11", orients={2}, weight={logcabin=1, single=1}, inh=6, typ='hut'},
|
||||||
|
{yoff= 0, scm="logcabinpub1", orients={1}, weight={logcabin=1/6, single=1}, pervillage=1, typ='tavern', axis=1, inh=1}, -- +5 guests
|
||||||
|
{yoff= 0, scm="logcabinpub2", orients={1}, weight={logcabin=1/6, single=1}, pervillage=1, typ='tavern', axis=1, inh=2}, -- +8 guests
|
||||||
|
{yoff= 0, scm="logcabinpub3", orients={1}, weight={logcabin=1/6, single=1}, pervillage=1, typ='tavern', axis=1, inh=2}, -- +12 guest
|
||||||
|
|
||||||
|
-- grass huts (requiring cottages, dryplants, cavestuff/undergrowth, plantlife)
|
||||||
|
{yoff= 0, scm="grasshut1", orients={2}, weight={grasshut=1, single=1}, inh=3, typ='hut'},
|
||||||
|
{yoff= 0, scm="grasshut2", orients={2}, weight={grasshut=1, single=1}, inh=10, typ='hut'}, -- community hut for meetings
|
||||||
|
{yoff= 0, scm="grasshut3", orients={2}, weight={grasshut=1, single=1}, inh=3, typ='hut'},
|
||||||
|
{yoff= 0, scm="grasshut4", orients={2}, weight={grasshut=1, single=1}, inh=3, typ='hut'},
|
||||||
|
{yoff= 0, scm="grasshut5", orients={2}, weight={grasshut=1, single=1}, inh=1, typ='hut'},
|
||||||
|
{yoff= 0, scm="grasshut6", orients={2}, weight={grasshut=1, single=1}, inh=3, typ='hut'},
|
||||||
|
{yoff= 0, scm="grasshutcenter", orients={2}, pervillage=1, weight={grasshut=2}, typ = 'tavern'}, -- open meeting place
|
||||||
|
|
||||||
|
-- for the buildings below, sizex, sizez and ysize are read from the file directly;
|
||||||
|
|
||||||
|
-- schematics from Sokomines villages mod (requires cottages)
|
||||||
|
{scm="church_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='church', weight={medieval=4 }, pervillage=1, inh=-1},
|
||||||
|
-- {scm="church_2_twoelk", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='church', weight={medieval=4}, pervillage=1},
|
||||||
|
{scm="forge_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='forge', weight={medieval=2, single=1/2}, pervillage=1, inh=-1},
|
||||||
|
{scm="mill_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='mill', weight={medieval=2 }, pervillage=1, inh=-1},
|
||||||
|
{scm="watermill_1", yoff=-3, orients={1}, farming_plus=0, avoid='', typ='mill', weight={medieval=2 }, pervillage=1, inh=-2},
|
||||||
|
{scm="hut_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='hut', weight={medieval=1, single=1 }, inh=1},
|
||||||
|
{scm="hut_2", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='hut', weight={medieval=1, single=1 }, inh=2},
|
||||||
|
{scm="farm_full_1", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=2},
|
||||||
|
{scm="farm_full_2", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=5},
|
||||||
|
{scm="farm_full_3", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=5},
|
||||||
|
{scm="farm_full_4", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=8},
|
||||||
|
{scm="farm_full_5", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=5},
|
||||||
|
{scm="farm_full_6", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='farm_full', weight={medieval=1/4, single=1 }, inh=5},
|
||||||
|
{scm="farm_tiny_1", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=2},
|
||||||
|
{scm="farm_tiny_2", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=6},
|
||||||
|
{scm="farm_tiny_3", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=4},
|
||||||
|
{scm="farm_tiny_4", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=4},
|
||||||
|
{scm="farm_tiny_5", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=4},
|
||||||
|
{scm="farm_tiny_6", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=4},
|
||||||
|
{scm="farm_tiny_7", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='farm_tiny', weight={medieval=1, single=1 }, inh=7},
|
||||||
|
{scm="taverne_1", yoff= 0, orients={0}, farming_plus=1, avoid='', typ='tavern', weight={medieval=1/2, single=1 }, pervillage=1, inh=6}, -- 19 beds: 10 guest, 3 worker, 6 family
|
||||||
|
{scm="taverne_2", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='tavern', weight={medieval=1/2, single=1/3}, pervillage=1, inh=2}, -- no guests
|
||||||
|
{scm="taverne_3", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='tavern', weight={medieval=1/2, single=1/3}, pervillage=1, inh=2}, -- no guests
|
||||||
|
{scm="taverne_4", yoff= 0, orients={0}, farming_plus=0, avoid='', typ='tavern', weight={medieval=1/2, single=1/3}, pervillage=1, inh=1}, -- no guests
|
||||||
|
|
||||||
|
{scm="well_1", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||||
|
{scm="well_2", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||||
|
{scm="well_3", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||||
|
{scm="well_4", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||||
|
{scm="well_5", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||||
|
{scm="well_6", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||||
|
{scm="well_7", yoff= -1, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||||
|
{scm="well_8", yoff= 0, orients={0}, farming_plus=0, avoid='well', typ='well', weight={medieval=1/12, single=1/2}, pervillage=4},
|
||||||
|
|
||||||
|
{scm="allmende_3_90", yoff=-2, orients={0}, farming_plus=0, avoid='', typ='allmende', weight={medieval=3,taoki=3,nore=3,logcabin=1,grasshut=1}, pervillage=1},
|
||||||
|
|
||||||
|
{scm="tree_place_1", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_2", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_3", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_4", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_5", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_6", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_7", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_8", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_9", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
{scm="tree_place_10", yoff= 1, orients={0}, farming_plus=0, avoid='', typ='village_square', weight={medieval=1/12}, pervillage=1},
|
||||||
|
|
||||||
|
{scm="wagon_1", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_2", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_3", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_4", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_5", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_6", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_7", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_8", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_9", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_10", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_11", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
{scm="wagon_12", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='wagon', weight={medieval=1/12,tent=1/3}, axis=1},
|
||||||
|
|
||||||
|
{scm="bench_1", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='bench', weight={medieval=1/12}, nomirror=1},
|
||||||
|
{scm="bench_2", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='bench', weight={medieval=1/12}, nomirror=1},
|
||||||
|
{scm="bench_3", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='bench', weight={medieval=1/12}, nomirror=1},
|
||||||
|
{scm="bench_4", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='bench', weight={medieval=1/12}, nomirror=1},
|
||||||
|
|
||||||
|
{scm="shed_1", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_2", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_3", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_5", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_6", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_7", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_8", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_9", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_10", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_11", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
{scm="shed_12", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='shed', weight={medieval=1/10}},
|
||||||
|
|
||||||
|
{scm="weide_1", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||||
|
{scm="weide_2", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||||
|
{scm="weide_3", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||||
|
{scm="weide_4", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||||
|
{scm="weide_5", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||||
|
{scm="weide_6", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='pasture', typ='pasture', weight={medieval=1/6}, pervillage=8},
|
||||||
|
|
||||||
|
{scm="field_1", yoff=-2, orients={0,1,2,3}, farming_plus=0, avoid='field', typ='field', weight={medieval=1/6}, pervillage=8},
|
||||||
|
{scm="field_2", yoff=-2, orients={0,1,2,3}, farming_plus=0, avoid='field', typ='field', weight={medieval=1/6}, pervillage=8},
|
||||||
|
{scm="field_3", yoff=-2, orients={0,1,2,3}, farming_plus=0, avoid='field', typ='field', weight={medieval=1/6}, pervillage=8},
|
||||||
|
{scm="field_4", yoff=-2, orients={0,1,2,3}, farming_plus=0, avoid='field', typ='field', weight={medieval=1/6}, pervillage=8},
|
||||||
|
|
||||||
|
-- hut and hills for charachoal burners; perhaps they could live together with lumberjacks?
|
||||||
|
{scm="charachoal_hut", yoff= 0, orients={0,1,2}, farming_plus=0, avoid='', typ='hut', weight={charachoal=1, single=5}, inh=2, nomirror=1},
|
||||||
|
{scm="charachoal_hill", yoff= 0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='hut', weight={charachoal=2 }, inh=-1, nomirror=1},
|
||||||
|
|
||||||
|
-- lumberjacks; they require the cottages mod
|
||||||
|
{scm="lumberjack_1", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=3},
|
||||||
|
{scm="lumberjack_2", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=4},
|
||||||
|
{scm="lumberjack_3", yoff= 1, orients={1,2,3}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, inh=3},
|
||||||
|
{scm="lumberjack_4", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=4},
|
||||||
|
{scm="lumberjack_5", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=9},
|
||||||
|
{scm="lumberjack_6", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=5},
|
||||||
|
{scm="lumberjack_7", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=5},
|
||||||
|
{scm="lumberjack_8", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=9},
|
||||||
|
{scm="lumberjack_9", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=5},
|
||||||
|
{scm="lumberjack_10", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||||
|
{scm="lumberjack_11", yoff= 0, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||||
|
{scm="lumberjack_12", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=3},
|
||||||
|
{scm="lumberjack_13", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=3},
|
||||||
|
{scm="lumberjack_14", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||||
|
{scm="lumberjack_15", yoff= 1, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||||
|
{scm="lumberjack_16", yoff= 0, orients={1}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=2},
|
||||||
|
{scm="lumberjack_school", yoff= 1, orients={1}, avoid='', typ='school', weight={lumberjack=2 }, axis=1, inh=1},
|
||||||
|
{scm="lumberjack_stable", yoff= 0, orients={3}, avoid='', typ='lumberjack', weight={lumberjack=1, single=3}, axis=1, inh=-1},
|
||||||
|
{scm="lumberjack_pub_1", yoff= 1, orients={1}, avoid='', typ='tavern', weight={lumberjack=3, single=1}, pervillage=1, axis=1, inh=-1},
|
||||||
|
{scm="lumberjack_church_1", yoff= 1, orients={1}, avoid='', typ='church', weight={lumberjack=3}, pervillage=1, axis=1, inh=-1},
|
||||||
|
{scm="lumberjack_hotel_1", yoff= 1, orients={1}, avoid='', typ='house', weight={lumberjack=1, single=1}, axis=1, inh=16}, -- all 16 are guests
|
||||||
|
{scm="lumberjack_shop_1", yoff= 1, orients={1}, avoid='', typ='shop', weight={lumberjack=1}, pervillage=1, axis=1, inh=-1},
|
||||||
|
{scm="lumberjack_sawmill_1",yoff=-7, orients={1}, avoid='', typ='sawmill', weight={lumberjack=2, single=1}, pervillage=1, axis=1, inh=-1},
|
||||||
|
|
||||||
|
|
||||||
|
-- {scm="cow_trader_1", yoff= 0, orients={4}, avoid='', typ='trader', weight={lumberjack=1}},
|
||||||
|
|
||||||
|
-- clay traders depend on cottages as well
|
||||||
|
{scm="trader_clay_1", yoff= 1, orients={1}, avoid='', typ='trader', weight={claytrader=3, single=3}, axis=1, inh=1}, -- poor guy who has to live in that small thing
|
||||||
|
{scm="trader_clay_2", yoff= 1, orients={3}, avoid='', typ='trader', weight={claytrader=3, single=3}, axis=1, inh=1}, -- not that he'll live very comftable there...
|
||||||
|
{scm="trader_clay_3", yoff= 1, orients={0}, avoid='', typ='trader', weight={claytrader=3, single=3}, inh=2},
|
||||||
|
{scm="trader_clay_4", yoff= 1, orients={2}, avoid='', typ='trader', weight={claytrader=3, single=3}, inh=2},
|
||||||
|
{scm="trader_clay_5", yoff= 1, orients={1}, avoid='', typ='trader', weight={claytrader=3, single=3}, axis=1, inh=2},
|
||||||
|
|
||||||
|
{scm="clay_pit_1", yoff=-3, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||||
|
{scm="clay_pit_2", yoff=-2, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||||
|
{scm="clay_pit_3", yoff=-7, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||||
|
{scm="clay_pit_4", yoff= 0, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||||
|
{scm="clay_pit_5", yoff= 1, orients={0,1,2,3}, avoid='', typ='pit', weight={claytrader=1}},
|
||||||
|
|
||||||
|
|
||||||
|
-- Houses from Taokis Structure I/O Mod (see https://forum.minetest.net/viewtopic.php?id=5524)
|
||||||
|
{scm="default_town_farm", yoff= -1, orients={1}, farming_plus=0, avoid='', typ='field', weight={taoki=1, single=1}, axis=1},
|
||||||
|
{scm="default_town_house_large_1", yoff= -4, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1/4, single=1}, axis=1, inh=10},
|
||||||
|
{scm="default_town_house_large_2", yoff= -4, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1/4, single=1}, axis=1, inh=8},
|
||||||
|
{scm="default_town_house_medium", yoff= -4, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1/2, single=1}, axis=1, inh=6},
|
||||||
|
{scm="default_town_house_small", yoff= -4, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1, single=1}, axis=1, inh=4},
|
||||||
|
{scm="default_town_house_tiny_1", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1, single=1}, axis=1, inh=3},
|
||||||
|
{scm="default_town_house_tiny_2", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1, single=1}, axis=1, inh=3},
|
||||||
|
{scm="default_town_house_tiny_3", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1, single=1}, axis=1, inh=2},
|
||||||
|
{scm="default_town_park", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='deco', weight={taoki=1 }, axis=1},
|
||||||
|
{scm="default_town_tower", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='tower', weight={taoki=1/6, single=1}, axis=1, inh=-1},
|
||||||
|
{scm="default_town_well", yoff= -6, orients={1}, farming_plus=0, avoid='', typ='well', weight={taoki=1/4 }, axis=1},
|
||||||
|
{scm="default_town_fountain", yoff= 1, orients={1}, farming_plus=0, avoid='', typ='fountain',weight={taoki=1/4 }, axis=1},
|
||||||
|
-- the hotel seems to be only the middle section of the building; it's build for another spawning algorithm
|
||||||
|
-- {scm="default_town_hotel", yoff= -1, orients={1}, farming_plus=0, avoid='', typ='house', weight={taoki=1/5}},
|
||||||
|
|
||||||
|
{scm="tent_tiny_1", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1, single=1}, inh=1},
|
||||||
|
{scm="tent_tiny_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1, single=1}, inh=1},
|
||||||
|
{scm="tent_big_1", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1, single=1}}, -- no sleeping place
|
||||||
|
{scm="tent_big_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1, single=1}, inh=2},
|
||||||
|
{scm="tent_medium_1", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/2, single=1}, inh=3},
|
||||||
|
{scm="tent_medium_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/2, single=1}, inh=3},
|
||||||
|
{scm="tent_medium_3", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/2, single=1}, inh=3},
|
||||||
|
{scm="tent_medium_4", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/2, single=1}, inh=3},
|
||||||
|
{scm="tent_open_1", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/5}},
|
||||||
|
{scm="tent_open_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/5}},
|
||||||
|
{scm="tent_open_3", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/5}},
|
||||||
|
{scm="tent_open_big_1", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/5}},
|
||||||
|
{scm="tent_open_big_2", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/5}},
|
||||||
|
{scm="tent_open_big_3", yoff=0, orients={3}, farming_plus=0, avoid='', typ='tent', weight={tent=1/5}},
|
||||||
|
|
||||||
|
{scm="hochsitz_1", yoff=0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='tower', weight={tower=1, single=1/3}, nomirror=1},
|
||||||
|
{scm="hochsitz_2", yoff=0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='tower', weight={tower=1, single=1/3}, nomirror=1},
|
||||||
|
{scm="hochsitz_3", yoff=0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='tower', weight={tower=1, single=1/3}, nomirror=1},
|
||||||
|
{scm="hochsitz_4", yoff=0, orients={0,1,2,3}, farming_plus=0, avoid='', typ='tower', weight={tower=1, single=1/3}, nomirror=1},
|
||||||
|
|
||||||
|
{scm="chateau_without_garden", yoff=-1,orients={0,1,2,3}, farming_plus=0, avoid='', typ='chateau', weight={chateau=1,single=8}, pervillage=1, inh=8},
|
||||||
|
|
||||||
|
{scm="baking_house_1", yoff=0, orients={0}, farming_plus=0, avoid='', typ='bakery', weight={medieval=1/4}, pervillage=1, inh=-1},
|
||||||
|
{scm="baking_house_2", yoff=0, orients={0}, farming_plus=0, avoid='', typ='bakery', weight={medieval=1/4}, pervillage=1, inh=-1},
|
||||||
|
{scm="baking_house_3", yoff=0, orients={0}, farming_plus=0, avoid='', typ='bakery', weight={medieval=1/4}, pervillage=1, inh=-1},
|
||||||
|
{scm="baking_house_4", yoff=0, orients={0}, farming_plus=0, avoid='', typ='bakery', weight={medieval=1/4}, pervillage=1, inh=-1},
|
||||||
|
|
||||||
|
{scm="empty_1", yoff=0, typ='empty', inh=0, pervillage=2,
|
||||||
|
weight={nore=1/8,taoki=1/8,medieval=1/8,charachoal=1/8,lumberjack=1/8,claytrader=1/8,logcabin=1/8,canadian=1/8,grasshut=1/8,tent=1/8}},
|
||||||
|
{scm="empty_2", yoff=0, typ='empty', inh=0, pervillage=2,
|
||||||
|
weight={nore=1/8,taoki=1/8,medieval=1/8,charachoal=1/8,lumberjack=1/8,claytrader=1/8,logcabin=1/8,canadian=1/8,grasshut=1/8,tent=1/8}},
|
||||||
|
{scm="empty_3", yoff=0, typ='empty', inh=0, pervillage=2,
|
||||||
|
weight={nore=1/8,taoki=1/8,medieval=1/8,charachoal=1/8,lumberjack=1/8,claytrader=1/8,logcabin=1/8,canadian=1/8,grasshut=1/8,tent=1/8}},
|
||||||
|
{scm="empty_4", yoff=0, typ='empty', inh=0, pervillage=2,
|
||||||
|
weight={nore=1/8,taoki=1/8,medieval=1/8,charachoal=1/8,lumberjack=1/8,claytrader=1/8,logcabin=1/8,canadian=1/8,grasshut=1/8,tent=1/8}},
|
||||||
|
{scm="empty_5", yoff=0, typ='empty', inh=0, pervillage=2,
|
||||||
|
weight={nore=1/8,taoki=1/8,medieval=1/8,charachoal=1/8,lumberjack=1/8,claytrader=1/8,logcabin=1/8,canadian=1/8,grasshut=1/8,tent=1/8}},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- 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 file_name = building_data.mts_path .. building_data.scm;
|
||||||
|
-- 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 typ ~= 'single' and mg_villages.village_type_data[ typ ] and mg_villages.village_type_data[ typ ].supported ) then
|
||||||
|
is_used = true;
|
||||||
|
end
|
||||||
|
-- add the building to the menu list for the build chest ("single" would be too many houses)
|
||||||
|
-- the empty plots are added to each village and of no intrest here
|
||||||
|
if( build_chest and build_chest.add_entry and typ and typ ~= 'single' and (not( building_data.typ ) or building_data.typ ~= 'empty')) then
|
||||||
|
build_chest.add_entry( {'main','mg_villages', typ, building_data.scm, file_name });
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- buildings as such may have a type as well
|
||||||
|
if( build_chest and build_chest.add_entry and building_data.typ ) then
|
||||||
|
build_chest.add_entry( {'main','mg_villages', building_data.typ, building_data.scm, file_name });
|
||||||
|
end
|
||||||
|
-- store information about all buildings - no matter weather they can be used or not - for later presentation in the build_chest's menu
|
||||||
|
if( build_chest and build_chest.add_building ) then
|
||||||
|
build_chest.add_building( file_name, building_data );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if( not( is_used )) then
|
||||||
|
-- do nothing; skip this file
|
||||||
|
mg_villages.print(mg_villages.DEBUG_LEVEL_INFO, '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;
|
||||||
|
-- convert to .mts for later usage if necessary
|
||||||
|
res = handle_schematics.analyze_file( file_name, building_data.we_origin, building_data.mts_path .. building_data.scm );
|
||||||
|
|
||||||
|
if( not( res )) then
|
||||||
|
mg_villages.print(mg_villages.DEBUG_LEVEL_WARNING, 'SKIPPING '..tostring( building_data.scm )..' due to import failure.');
|
||||||
|
building_data.not_available = 1;
|
||||||
|
return false;
|
||||||
|
-- provided the file could be analyzed successfully (now covers both .mts and .we files)
|
||||||
|
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( not( building_data.orients ) and res.rotated ) then
|
||||||
|
building_data.orients = {};
|
||||||
|
if( res.rotated == 0 ) then
|
||||||
|
building_data.orients[1] = 0;
|
||||||
|
elseif( res.rotated == 90 ) then
|
||||||
|
building_data.axis = 1; -- important when mirroring
|
||||||
|
building_data.orients[1] = 1;
|
||||||
|
elseif( res.rotated == 180 ) then
|
||||||
|
building_data.orients[1] = 2;
|
||||||
|
elseif( res.rotated == 270 ) then
|
||||||
|
building_data.orients[1] = 3;
|
||||||
|
building_data.axis = 1; -- important when mirroring
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if( not( building_data.yoff ) and res.burried ) then
|
||||||
|
building_data.yoff = 1-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
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
mg_villages.print( mg_villages.DEBUG_LEVEL_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
|
||||||
|
mg_villages.print( mg_villages.DEBUG_LEVEL_WARNING, 'SKIPPING '..tostring( building_data.scm )..' due to missing weight information.');
|
||||||
|
building_data.not_available = 1;
|
||||||
|
return false;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- handle duplicates; make sure buildings always get the same number;
|
||||||
|
-- check if the building has been used in previous runs and got an ID there
|
||||||
|
|
||||||
|
-- create a not very unique, but for this case sufficient "id";
|
||||||
|
-- (buildings with the same size and name are considered to be drop-in-replacements
|
||||||
|
local building_id = building_data.sizex..'x'..building_data.sizez..'_'..building_data.scm;
|
||||||
|
-- if the building is new, it will get the next free id
|
||||||
|
local building_nr = #mg_villages.all_buildings_list + 1;
|
||||||
|
for i,v in ipairs( mg_villages.all_buildings_list ) do
|
||||||
|
if( v==building_id ) then
|
||||||
|
-- we found the building
|
||||||
|
building_nr = i;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if it is a new building, then save the list
|
||||||
|
if( building_nr == #mg_villages.all_buildings_list+1 ) then
|
||||||
|
mg_villages.all_buildings_list[ building_nr ] = building_id;
|
||||||
|
-- save information about previously imported buildings
|
||||||
|
save_restore.save_data( 'mg_villages_all_buildings_list.data', mg_villages.all_buildings_list );
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
-- actually store the building data
|
||||||
|
mg_villages.BUILDINGS[ building_nr ] = 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 ] = building_nr;
|
||||||
|
data.max_weight_list[ index ] = total_weight + building_data.weight[ typ ];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- print it for debugging usage
|
||||||
|
--print( building_data.scm .. ': '..tostring(building_data.sizex)..' x '..tostring(building_data.sizez)..' x '..tostring(building_data.ysize)..' h');
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- this list contains some information about previously imported buildings so that they will get the same id
|
||||||
|
mg_villages.all_buildings_list = save_restore.restore_data( 'mg_villages_all_buildings_list.data' );
|
||||||
|
|
||||||
|
-- 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( buildings ) do
|
||||||
|
v.mts_path = mts_path;
|
||||||
|
mg_villages.add_building( v, i );
|
||||||
|
end
|
||||||
|
buildings = nil;
|
||||||
|
|
||||||
|
-- roads are built in a diffrent way
|
||||||
|
mg_villages.BUILDINGS["road"] = {yoff = 0, ysize = 2, scm = {}}
|
107
mods/a_mapgen_mods/mg_villages/chat_commands.lua
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
minetest.register_privilege("mg_villages", { description = "Allows to teleport to villages via /vist <nr>", give_to_singleplayer = false});
|
||||||
|
|
||||||
|
-- this function is only used for the chat command currently
|
||||||
|
mg_villages.list_villages_formspec = function( player, formname, fields )
|
||||||
|
|
||||||
|
if( not( player ) or fields.quit) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pname = player:get_player_name();
|
||||||
|
local ppos = player:getpos();
|
||||||
|
|
||||||
|
|
||||||
|
local radius = 1000000;
|
||||||
|
-- without the special priv, players can only obtain informatoin about villages which are very close by
|
||||||
|
if( not( minetest.check_player_privs( pname, {mg_villages=true}))) then
|
||||||
|
radius = mg_villages.VILLAGE_DETECT_RANGE;
|
||||||
|
end
|
||||||
|
|
||||||
|
local formspec = 'size[12,12]'..
|
||||||
|
'button_exit[4.0,1.5;2,0.5;quit;Quit]'..
|
||||||
|
'tablecolumns[' ..
|
||||||
|
'text,align=right;'.. -- village number
|
||||||
|
'text,align=right;'.. -- distance from player
|
||||||
|
'text,align=center;'.. -- name of village
|
||||||
|
'text,align=center;'.. -- typ of village
|
||||||
|
'text,align=right;'.. -- x
|
||||||
|
'text,align=right;'.. -- y
|
||||||
|
'text,align=right;'.. -- z
|
||||||
|
'text,align=right;'.. -- size
|
||||||
|
'text,align=right;'.. -- #houses where inhabitants may live or work
|
||||||
|
'text,align=right]'..
|
||||||
|
'table[0.1,2.7;11.4,8.8;'..formname..';';
|
||||||
|
|
||||||
|
for k,v in pairs( mg_villages.all_villages ) do
|
||||||
|
|
||||||
|
local dx = math.abs( v.vx - ppos.x );
|
||||||
|
local dz = math.abs( v.vz - ppos.z );
|
||||||
|
-- distance in y direction is less relevant here and may be ignored
|
||||||
|
if( dx + dz < radius ) then
|
||||||
|
local dist = math.sqrt( dx * dx + dz * dz );
|
||||||
|
local is_full_village = 'village';
|
||||||
|
if( v.is_single_house ) then
|
||||||
|
is_full_village = '';
|
||||||
|
end
|
||||||
|
formspec = formspec..
|
||||||
|
v.nr..','..
|
||||||
|
tostring( math.floor( dist ))..','..
|
||||||
|
tostring( v.name or 'unknown' )..','..
|
||||||
|
v.village_type..','..
|
||||||
|
tostring( v.vx )..','..
|
||||||
|
tostring( v.vh )..','..
|
||||||
|
tostring( v.vz )..','..
|
||||||
|
tostring( v.vs )..','..
|
||||||
|
tostring( v.anz_buildings )..','..
|
||||||
|
tostring( is_full_village )..',';
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
formspec = formspec..';]'..
|
||||||
|
'tabheader[0.1,2.2;spalte;Nr,Dist,Name of village,Type of village,_X_,_H_,_Z_,Size,Buildings;;true;true]';
|
||||||
|
|
||||||
|
minetest.show_formspec( pname, formname, formspec );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_chatcommand( 'villages', {
|
||||||
|
description = "Shows a list of all known villages.",
|
||||||
|
privs = {},
|
||||||
|
func = function(name, param)
|
||||||
|
mg_villages.list_villages_formspec( minetest.get_player_by_name( name ), "mg:village_list", {});
|
||||||
|
end
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_chatcommand( 'visit', {
|
||||||
|
description = "Teleports you to a known village.",
|
||||||
|
params = "<village number>",
|
||||||
|
privs = {},
|
||||||
|
func = function(name, param)
|
||||||
|
|
||||||
|
|
||||||
|
if( mg_villages.REQUIRE_PRIV_FOR_TELEPORT and not( minetest.check_player_privs( name, {mg_villages=true}))) then
|
||||||
|
minetest.chat_send_player( name, "You need the 'mg_villages' priv in order to teleport to villages using this command.");
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
if( not( param ) or param == "" ) then
|
||||||
|
minetest.chat_send_player( name, "Which village do you want to visit? Please provide the village number!");
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local nr = tonumber( param );
|
||||||
|
for id, v in pairs( mg_villages.all_villages ) do
|
||||||
|
-- we have found the village
|
||||||
|
if( v and v.nr == nr ) then
|
||||||
|
|
||||||
|
minetest.chat_send_player( name, "Initiating transfer to village no. "..tostring( v.nr )..", called "..( tostring( v.name or 'unknown'))..".");
|
||||||
|
local player = minetest.get_player_by_name( name );
|
||||||
|
player:moveto( { x=v.vx, y=(v.vh+1), z=v.vz }, false);
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- no village found
|
||||||
|
minetest.chat_send_player( name, "There is no village with the number "..tostring( param ).." (yet?).");
|
||||||
|
end
|
||||||
|
});
|
187
mods/a_mapgen_mods/mg_villages/config.lua
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- configuration values which you can adjust according to your liking
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- set to false if you do not want to have any villages spawning
|
||||||
|
mg_villages.ENABLE_VILLAGES = true;
|
||||||
|
|
||||||
|
-- generate one random building for each mg_villages.INVERSE_HOUSE_DENSITY th mapchunk;
|
||||||
|
-- set to 0 in order to disable spawning of these lone buildings outside villages
|
||||||
|
mg_villages.INVERSE_HOUSE_DENSITY = 0;
|
||||||
|
|
||||||
|
-- cover some villages with artificial snow; probability: 1/mg_villages.artificial_snow_probability
|
||||||
|
mg_villages.artificial_snow_probability = 0;
|
||||||
|
|
||||||
|
-- if set to true, soil around villaes will get special soil-snow instead of plant + snow cover
|
||||||
|
mg_villages.use_soil_snow = false;
|
||||||
|
|
||||||
|
-- only place roads if there are at least that many buildings in the village
|
||||||
|
mg_villages.MINIMAL_BUILDUNGS_FOR_ROAD_PLACEMENT = 4;
|
||||||
|
|
||||||
|
|
||||||
|
-- players without the mg_villages priv can only see villages which are less than that many blocks away
|
||||||
|
-- from them when using the /vmap command
|
||||||
|
mg_villages.VILLAGE_DETECT_RANGE = 400;
|
||||||
|
|
||||||
|
-- if set to true, only players which have the mg_villages priv can use the "/visit <village nr>"
|
||||||
|
-- command which allows teleporting to the village with the given number
|
||||||
|
mg_villages.REQUIRE_PRIV_FOR_TELEPORT = false;
|
||||||
|
|
||||||
|
-- if set to true, players cannot modify spawned villages without buying the house from the village first
|
||||||
|
mg_villages.ENABLE_PROTECTION = false;
|
||||||
|
|
||||||
|
-- the first village - the one the player spawns in - will be of this type
|
||||||
|
mg_villages.FIRST_VILLAGE_TYPE = 'ruins';
|
||||||
|
|
||||||
|
-- the mapgen will disregard mapchunks where min.y > mg_villages.MAX_HEIGHT_TREATED;
|
||||||
|
-- you can set this value to 64 if you have a slow machine and a mapgen which does not create extreme mountains
|
||||||
|
-- (or if you don't care if extreme mountains may create burried villages occasionally)
|
||||||
|
mg_villages.MAX_HEIGHT_TREATED = 64;
|
||||||
|
|
||||||
|
-- choose the debug level you want
|
||||||
|
mg_villages.DEBUG_LEVEL = mg_villages.DEBUG_LEVEL_NORMAL
|
||||||
|
|
||||||
|
-- if set to true (or anything else but nil or false), highlandpools by paramat (see
|
||||||
|
-- https://forum.minetest.net/viewtopic.php?t=8400) will be created
|
||||||
|
mg_villages.CREATE_HIGHLANDPOOLS = true
|
||||||
|
|
||||||
|
-- background image for the /vmap command
|
||||||
|
-- RealTest comes with a diffrent texture
|
||||||
|
if( minetest.get_modpath('grounds') and minetest.get_modpath('joiner_table')) then
|
||||||
|
mg_villages.MAP_BACKGROUND_IMAGE = "default_dirt_grass.png";
|
||||||
|
elseif( minetest.registered_nodes[ 'default:dirt_with_grass'] ) then
|
||||||
|
mg_villages.MAP_BACKGROUND_IMAGE = "default_grass.png";
|
||||||
|
else
|
||||||
|
mg_villages.MAP_BACKGROUND_IMAGE = "";
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if set to true, the outer buildings in medieval villages will be fields; this is not very convincing yet
|
||||||
|
-- currently not really used; does not look as good as expected
|
||||||
|
mg_villages.medieval_subtype = false;
|
||||||
|
|
||||||
|
-- set this to true if you want to use normal lava - but beware: charachoal villages may cause bushfires!
|
||||||
|
mg_villages.use_normal_unsafe_lava = true;
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- decrese these values slightly if you want MORE trees around your villages;
|
||||||
|
-- increase it if you want to DECREASE the amount of trees around villages
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- on average, every n.th node inside a village area may be one of these trees - and it will be a relatively dense packed forrest
|
||||||
|
mg_villages.sapling_probability = {};
|
||||||
|
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'default:sapling' ) ] = 10; -- suitable for a relatively dense forrest of normal trees
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'default:junglesapling' ) ] = 10; -- jungletrees are a bit bigger and need more space
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'default:pinesapling' ) ] = 10;
|
||||||
|
if( minetest.get_modpath( 'mg' )) then
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'mg:savannasapling' ) ] = 10;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'mg:pinesapling' ) ] = 10;
|
||||||
|
end
|
||||||
|
mg_villages.moretrees_treelist = nil;
|
||||||
|
if( minetest.get_modpath( 'moretrees' )) then
|
||||||
|
mg_villages.moretrees_treelist = moretrees.treelist;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:birch_sapling_ongen' ) ] = 200;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:spruce_sapling_ongen' ) ] = 200;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:fir_sapling_ongen' ) ] = 90;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:jungletree_sapling_ongen' ) ] = 200;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:beech_sapling_ongen' ) ] = 30;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:apple_sapling_ongen' ) ] = 380;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:oak_sapling_ongen' ) ] = 380; -- ca 20x20; height: 10
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:sequoia_sapling_ongen' ) ] = 90; -- ca 10x10
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:palm_sapling_ongen' ) ] = 90;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:pine_sapling_ongen' ) ] = 200;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:willow_sapling_ongen' ) ] = 380;
|
||||||
|
mg_villages.sapling_probability[ minetest.get_content_id( 'moretrees:rubber_tree_sapling_ongen' ) ] = 380;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- no need to change this, unless you add new farming_plus fruits
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- the schematics for buildings of type 'farm_tiny' grow cotton; the farming_plus fruits would be far more fitting
|
||||||
|
mg_villages.fruit_list = {'carrot','potatoe','orange','rhubarb','strawberry','tomato','cotton'};
|
||||||
|
-- is farming_plus available? If not, we can't use this
|
||||||
|
if( not( minetest.get_modpath("farming_plus"))) then
|
||||||
|
mg_villages.fruit_list = nil;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- players can buy plots in villages with houses on for this price;
|
||||||
|
-- set according to your liking
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- how much does the player have to pay for a plot with a building?
|
||||||
|
mg_villages.prices = {
|
||||||
|
empty = "default:copper_ingot 1", -- plot to build on
|
||||||
|
|
||||||
|
-- building types which usually have inhabitants (and thus allow the player
|
||||||
|
-- who bought the building to modifiy the entire village area minus other
|
||||||
|
-- buildings)
|
||||||
|
tent = "default:copper_ingot 1",
|
||||||
|
hut = "default:copper_ingot 1",
|
||||||
|
farm_full = "default:gold_ingot 4",
|
||||||
|
farm_tiny = "default:gold_ingot 2",
|
||||||
|
lumberjack = "default:gold_ingot 2",
|
||||||
|
house = "default:gold_ingot 2",
|
||||||
|
house_large = "default:gold_ingot 4",
|
||||||
|
tavern = "default:gold_ingot 12",
|
||||||
|
trader = "default:gold_ingot 2",
|
||||||
|
|
||||||
|
-- more or less community buildings
|
||||||
|
well = "default:gold_ingot 1",
|
||||||
|
village_square = "default:goldblock 1",
|
||||||
|
secular = "default:goldblock 2", -- secular buildings, such as libraries ec.
|
||||||
|
church = "default:goldblock 10",
|
||||||
|
|
||||||
|
-- places for mobs to work at; usually without inhabitants
|
||||||
|
tower = "default:copper_ingot 1",
|
||||||
|
shed = "default:copper_ingot 2",
|
||||||
|
pit = "default:copper_ingot 3", -- claytrader pit
|
||||||
|
mill = "default:gold_ingot 10",
|
||||||
|
forge = "default:gold_ingot 10",
|
||||||
|
bakery = "default:gold_ingot 10",
|
||||||
|
shop = "default:gold_ingot 20",
|
||||||
|
sawmill = "default:gold_ingot 30",
|
||||||
|
|
||||||
|
-- decoration
|
||||||
|
wagon = "default:tree 10",
|
||||||
|
bench = "default:tree 4",
|
||||||
|
|
||||||
|
-- seperate fields
|
||||||
|
pasture = "default:copper_ingot 2",
|
||||||
|
field = "default:copper_ingot 2",
|
||||||
|
|
||||||
|
-- chateaus are expensive
|
||||||
|
chateau = "default:diamondblock 5",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- The values below seldom need adjustment; don't change them unless you
|
||||||
|
-- know exactly what you are doing.
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
-- if set to false, villages will not be integrated into the terrain - which looks very bad
|
||||||
|
mg_villages.ENABLE_TERRAIN_BLEND = true;
|
||||||
|
-- if set to false, holes digged by cavegen and mudflow inside the village will not be repaired; houses will be destroyed
|
||||||
|
mg_villages.UNDO_CAVEGEN_AND_MUDFLOW =true;
|
||||||
|
|
||||||
|
-- internal variables for village generation
|
||||||
|
|
||||||
|
mg_villages.VILLAGE_CHECK_RADIUS = 2
|
||||||
|
mg_villages.VILLAGE_CHECK_COUNT = 1
|
||||||
|
--mg_villages.VILLAGE_CHANCE = 28
|
||||||
|
--mg_villages.VILLAGE_MIN_SIZE = 20
|
||||||
|
--mg_villages.VILLAGE_MAX_SIZE = 40
|
||||||
|
mg_villages.VILLAGE_CHANCE = 28
|
||||||
|
-- min and max size are only used in case of them beeing not provided by the village type (see buildings.lua)
|
||||||
|
mg_villages.VILLAGE_MIN_SIZE = 25
|
||||||
|
mg_villages.VILLAGE_MAX_SIZE = 90 --55
|
||||||
|
mg_villages.FIRST_ROADSIZE = 3
|
||||||
|
mg_villages.BIG_ROAD_CHANCE = 0
|
||||||
|
|
||||||
|
-- Enable that for really big villages (there are also really slow to generate)
|
||||||
|
--[[mg_villages.VILLAGE_CHECK_RADIUS = 3
|
||||||
|
mg_villages.VILLAGE_CHECK_COUNT = 3
|
||||||
|
mg_villages.VILLAGE_CHANCE = 28
|
||||||
|
mg_villages.VILLAGE_MIN_SIZE = 100
|
||||||
|
mg_villages.VILLAGE_MAX_SIZE = 150
|
||||||
|
mg_villages.FIRST_ROADSIZE = 5
|
||||||
|
mg_villages.BIG_ROAD_CHANCE = 50]]
|
22
mods/a_mapgen_mods/mg_villages/depends.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
handle_schematics
|
||||||
|
default
|
||||||
|
doors?
|
||||||
|
farming?
|
||||||
|
wool?
|
||||||
|
stairs?
|
||||||
|
cottages?
|
||||||
|
moretrees?
|
||||||
|
trees?
|
||||||
|
forest?
|
||||||
|
dryplants?
|
||||||
|
cavestuff?
|
||||||
|
snow?
|
||||||
|
moresnow?
|
||||||
|
darkage?
|
||||||
|
ethereal?
|
||||||
|
deco?
|
||||||
|
metals?
|
||||||
|
grounds?
|
||||||
|
moreblocks?
|
||||||
|
bell?
|
||||||
|
mg?
|
228
mods/a_mapgen_mods/mg_villages/fill_chest--orig.lua
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
-- TODO: refill chest after some time?
|
||||||
|
-- TODO: alert NPC that something was taken
|
||||||
|
|
||||||
|
mg_villages.random_chest_content = {};
|
||||||
|
|
||||||
|
-- add random chest content
|
||||||
|
local ADD_RCC = function( data )
|
||||||
|
if( data and #data>3 and ( minetest.registered_nodes[ data[1] ] or minetest.registered_items[ data[1] ]) ) then
|
||||||
|
table.insert( mg_villages.random_chest_content, data );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- things that can be found in private, not locked chests belonging to npc
|
||||||
|
-- contains tables of the following structure: { node_name, probability (in percent, 100=always, 0=never), max_amount, repeat (for more than one stack) }
|
||||||
|
mg_villages.random_chest_content = {};
|
||||||
|
|
||||||
|
ADD_RCC({"default:pick_stone", 10, 1, 3, farm_tiny=1, farm_full=1, shed=1, lumberjack=1, hut=1, chest_work=1, lumberjack=1 });
|
||||||
|
ADD_RCC({"default:pick_steel", 5, 1, 2, forge=1 });
|
||||||
|
ADD_RCC({"default:pick_mese", 2, 1, 2, forge=1, lumberjack=1 });
|
||||||
|
ADD_RCC({"default:shovel_stone", 5, 1, 3, farm_tiny=1, farm_full=1, shed=1, lumberjack=1, hut=1, chest_work=1 });
|
||||||
|
ADD_RCC({"default:shovel_steel", 5, 1, 2, forge=1 });
|
||||||
|
ADD_RCC({"default:axe_stone", 5, 1, 3, farm_tiny=1, farm_full=1, chest_work=1, lumberjack=1 });
|
||||||
|
ADD_RCC({"default:axe_steel", 5, 1, 2, forge=1, lumberjack=1 });
|
||||||
|
ADD_RCC({"default:sword_wood", 1, 1, 3, guard=1 });
|
||||||
|
ADD_RCC({"default:sword_stone", 1, 1, 3, guard=1 });
|
||||||
|
ADD_RCC({"default:sword_steel", 1, 1, 3, forge=1, guard=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"default:stick", 20, 40, 2, church=1, library=1, chest_private=1, shelf=5, shed=1, lumberjack=1, hut=1 });
|
||||||
|
ADD_RCC({"default:torch", 50, 10, 4, church=1, library=1, chest_private=1, shelf=1, shed=1, lumberjack=1, hut=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"default:book", 60, 1, 2, church=1, library=1 });
|
||||||
|
ADD_RCC({"default:paper", 60, 6, 4, church=1, library=1 });
|
||||||
|
ADD_RCC({"default:apple", 50, 10, 2, chest_storage=4, chest_private=1, shelf=5});
|
||||||
|
ADD_RCC({"default:ladder", 20, 1, 2, church=1, library=1, shed=1, lumberjack=1, hut=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"default:coal_lump", 80, 30, 1, forge=1, shed=1, lumberjack=1, hut=1});
|
||||||
|
ADD_RCC({"default:steel_ingot", 30, 4, 2, forge=1 });
|
||||||
|
ADD_RCC({"default:mese_crystal_fragment", 10, 3, 1, forge=1, chest_storage=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"bucket:bucket_empty", 10, 3, 2, chest_work=1, forge=1, shed=1, hut=1 });
|
||||||
|
ADD_RCC({"bucket:bucket_water", 5, 3, 2, chest_work=1, forge=1 });
|
||||||
|
ADD_RCC({"bucket:bucket_lava", 3, 3, 2, forge=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"vessels:glass_bottle", 10, 10, 2, church=1, library=1, shelf=1 });
|
||||||
|
ADD_RCC({"vessels:drinking_glass", 20, 2, 1, church=1, library=1, shelf=1 });
|
||||||
|
ADD_RCC({"vessels:steel_bottle", 10, 1, 1, church=1, library=1, shelf=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"wool:white", 60, 8, 2, church=1, library=1 });
|
||||||
|
|
||||||
|
|
||||||
|
-- that someone will hide valuable ingots in chests that are not locked is fairly unrealistic; thus, those items are rare
|
||||||
|
ADD_RCC({"moreores:gold_ingot", 1, 2, 1 });
|
||||||
|
ADD_RCC({"moreores:silver_ingot", 1, 2, 1 });
|
||||||
|
ADD_RCC({"moreores:copper_ingot", 30, 10, 1 });
|
||||||
|
ADD_RCC({"moreores:tin_ingot", 1, 5, 1 });
|
||||||
|
ADD_RCC({"moreores:bronze_ingot", 1, 1, 1 });
|
||||||
|
ADD_RCC({"moreores:mithril_ingot", 1, 1, 1 });
|
||||||
|
|
||||||
|
-- candles are a very likely content of chests
|
||||||
|
ADD_RCC({"candles:candle", 80, 12, 2, church=1, library=1, chest_private=1 });
|
||||||
|
ADD_RCC({"candles:candelabra_steel", 1, 1, 1, church=1, library=1, chest_private=1 });
|
||||||
|
ADD_RCC({"candles:candelabra_copper", 1, 1, 1, church=1, library=1, chest_private=1 });
|
||||||
|
ADD_RCC({"candles:honey", 50, 2, 1 });
|
||||||
|
|
||||||
|
-- our NPC have to spend their free time somehow...also adds food variety
|
||||||
|
ADD_RCC({"fishing:pole", 60, 1, 1 });
|
||||||
|
|
||||||
|
-- ropes are always useful
|
||||||
|
if( minetest.get_modpath("ropes") ~= nil ) then
|
||||||
|
ADD_RCC({"ropes:rope", 60, 5, 2, chest_work=1, shelf=1, chest_storage=1 });
|
||||||
|
elseif( minetest.get_modpath("farming") ~= nil ) then
|
||||||
|
ADD_RCC({"farming:string", 60, 5, 2, church=1, library=1, chest_work=1, shelf=1, chest_storage=1 });
|
||||||
|
elseif( minetest.get_modpath("moreblocks") ~= nil ) then
|
||||||
|
ADD_RCC({"moreblocks:rope", 60, 5, 2, chest_work=1, shelf=1, chest_storage=1 });
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
ADD_RCC({'bees:bottle_honey', 50, 4, 1, beekeeper=3, tavern=1, inn=1, chest_storage=1 });
|
||||||
|
ADD_RCC({'bees:extractor', 80, 1, 2, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:frame_empty', 50, 2, 5, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:frame_full', 80, 1, 1, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:grafting_tool', 50, 1, 3, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:hive_industrial', 100, 1, 1, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:honey_comb', 50, 2, 2, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:queen_bee', 50, 2, 3, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:smoker', 80, 1, 2, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:wax', 80, 3, 3, beekeeper=1 });
|
||||||
|
|
||||||
|
ADD_RCC({'bushes:blackberry', 80, 20, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:blackberry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:blueberry', 80, 20, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:blueberry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:gooseberry', 80, 20, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:gooseberry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:raspberry', 80, 20, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:raspberry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:mixed_berry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:sugar', 80, 99, 5, bakery=1, shelf=1 });
|
||||||
|
|
||||||
|
ADD_RCC({'carts:cart', 80, 1, 2, miner=1});
|
||||||
|
|
||||||
|
ADD_RCC({'castle:battleaxe', 50, 1, 1, guard=1, forge=1 });
|
||||||
|
ADD_RCC({'castle:ropebox', 50, 2, 2, guard=1 });
|
||||||
|
ADD_RCC({'castle:ropes', 50, 1, 1, guard=2, chest_private=1, chest_work=2 });
|
||||||
|
ADD_RCC({'castle:shield', 50, 1, 1, guard=1 });
|
||||||
|
ADD_RCC({'castle:shield_2', 50, 1, 1, guard=1 });
|
||||||
|
ADD_RCC({'castle:shield_3', 50, 1, 1, guard=1 });
|
||||||
|
|
||||||
|
ADD_RCC({'cottages:anvil', 80, 1, 2, forge=1 });
|
||||||
|
|
||||||
|
ADD_RCC({'currency:minegeld', 80, 10, 2, chest_private=1, chest_work=1 }); -- TODO: could be in any chest with a certain chance
|
||||||
|
|
||||||
|
ADD_RCC({'farming:hoe_stone', 80, 1, 2, farm_tiny=2, farm_full=2, chest_work=2 });
|
||||||
|
|
||||||
|
ADD_RCC({'homedecor:beer_mug', 50, 1, 2, tavern=5, inn=3});
|
||||||
|
ADD_RCC({'homedecor:book_blue', 50, 1, 2, church=1, library=1, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:book_red', 50, 1, 2, church=1, library=1, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:book_green', 50, 1, 2, church=1, library=1, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:bottle_brown', 50, 1, 2, tavern=3, inn=3, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:bottle_green', 50, 1, 2, tavern=3, inn=3, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:calendar', 50, 1, 1, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1});
|
||||||
|
ADD_RCC({"homedecor:candle", 50, 2, 1, church=2, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
ADD_RCC({"homedecor:candle_thin", 50, 2, 1, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
ADD_RCC({"homedecor:copper_pans", 80, 1, 1, chest_work=1 });
|
||||||
|
ADD_RCC({"homedecor:dardboard", 50, 1, 1, tavern=1});
|
||||||
|
ADD_RCC({"homedecor:oil_extract", 80, 1, 3, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
ADD_RCC({"homedecor:oil_lamp", 50, 2, 1, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
ADD_RCC({"homedecor:torch_wall", 50, 2, 1, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"locks:key", 50, 2, 1, chest_private=1, chest_work=1, chest_storage=1, forge=1 });
|
||||||
|
ADD_RCC({"locks:keychain", 50, 2, 1, chest_private=1, chest_work=1, chest_storage=1, forge=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"moretrees:coconut_milk", 80, 5, 2, tavern=1, inn=1 });
|
||||||
|
ADD_RCC({"moretrees:raw_coconut", 80, 5, 2, tavern=1, inn=1 });
|
||||||
|
ADD_RCC({"moretrees:pine_nuts", 80, 99, 1, tavern=1, inn=1, chest_storage=3 });
|
||||||
|
ADD_RCC({"moretrees:spruce_nuts", 80, 99, 1, tavern=1, inn=1, chest_storage=3 });
|
||||||
|
|
||||||
|
ADD_RCC({"quartz:quartz_crystal", 80, 1, 1, library=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"screwdriver:screwdriver", 80, 1, 1, chest_work=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"unified_inventory:bag_large", 80, 1, 1, chest_private=1, chest_storage=2 });
|
||||||
|
ADD_RCC({"unified_inventory:bag_medium", 80, 1, 1, chest_private=1, chest_storage=2 });
|
||||||
|
ADD_RCC({"unified_inventory:bag_small", 80, 1, 1, tavern=1, inn=1, chest_work=1, chest_private=1 });
|
||||||
|
|
||||||
|
|
||||||
|
-- get some random content for a chest
|
||||||
|
mg_villages.fill_chest_random = function( pos, pr, building_nr, building_typ )
|
||||||
|
|
||||||
|
local building_data = mg_villages.BUILDINGS[ building_nr.btype ];
|
||||||
|
|
||||||
|
local meta = minetest.env:get_meta( pos );
|
||||||
|
local inv = meta:get_inventory();
|
||||||
|
|
||||||
|
local count = 0;
|
||||||
|
|
||||||
|
local typ = minetest.get_name_from_content_id( pos.typ );
|
||||||
|
if( pos.typ_name ) then
|
||||||
|
typ = pos.typ_name;
|
||||||
|
end
|
||||||
|
if( not( typ ) or (typ ~= 'cottages:shelf' and typ ~= 'cottages:chest_work' and typ ~= 'cottages:chest_storage' and typ ~= 'cottages:chest_private' )) then
|
||||||
|
typ = building_data.typ;
|
||||||
|
else
|
||||||
|
typ = string.sub( typ, 10 );
|
||||||
|
end
|
||||||
|
local typ2 = nil;
|
||||||
|
if( typ == 'cottages:chest_work' and building_data.typ ) then
|
||||||
|
typ2 = building_data.typ;
|
||||||
|
end
|
||||||
|
--print('FILLING chest of type '..tostring( typ )..' and '..tostring( typ2));
|
||||||
|
if( not( typ ) or typ=='' ) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
local inv_size = inv:get_size('main');
|
||||||
|
for i,v in ipairs( mg_villages.random_chest_content ) do
|
||||||
|
|
||||||
|
-- repeat this many times
|
||||||
|
for count=1, v[ 4 ] do
|
||||||
|
|
||||||
|
-- to avoid too many things inside a chest, lower probability
|
||||||
|
if( count<30 -- make sure it does not get too much and there is still room for a new stack
|
||||||
|
and (v[ typ ] or (typ2 and v[ typ2 ]))
|
||||||
|
and inv_size and inv_size > 0 and v[ 2 ] > pr:next( 1, 200 )) then
|
||||||
|
|
||||||
|
--inv:add_item('main', v[ 1 ].." "..tostring( math.random( 1, tonumber(v[ 3 ]) )));
|
||||||
|
-- add itemstack at a random position in the chests inventory
|
||||||
|
inv:set_stack( 'main', pr:next( 1, inv:get_size( 'main' )), v[ 1 ].." "..tostring( pr:next( 1, tonumber(v[ 3 ]) )) );
|
||||||
|
count = count+1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
--the old code used by Nores mg mapgen
|
||||||
|
for _, n in pairs(village.to_add_data.extranodes) do
|
||||||
|
|
||||||
|
-- minetest.set_node(n.pos, n.node)
|
||||||
|
if n.meta ~= nil then
|
||||||
|
|
||||||
|
|
||||||
|
meta = minetest.get_meta(n.pos)
|
||||||
|
meta:from_table(n.meta)
|
||||||
|
if n.node.name == "default:chest" then
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
local items = inv:get_list("main")
|
||||||
|
for i=1, inv:get_size("main") do
|
||||||
|
inv:set_stack("main", i, ItemStack(""))
|
||||||
|
end
|
||||||
|
local numitems = pr:next(3, 20)
|
||||||
|
for i=1,numitems do
|
||||||
|
local ii = pr:next(1, #items)
|
||||||
|
local prob = items[ii]:get_count() % 2 ^ 8
|
||||||
|
local stacksz = math.floor(items[ii]:get_count() / 2 ^ 8)
|
||||||
|
if pr:next(0, prob) == 0 and stacksz>0 then
|
||||||
|
stk = ItemStack({name=items[ii]:get_name(), count=pr:next(1, stacksz), wear=items[ii]:get_wear(), metadata=items[ii]:get_metadata()})
|
||||||
|
local ind = pr:next(1, inv:get_size("main"))
|
||||||
|
while not inv:get_stack("main",ind):is_empty() do
|
||||||
|
ind = pr:next(1, inv:get_size("main"))
|
||||||
|
end
|
||||||
|
inv:set_stack("main", ind, stk)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--]]
|
283
mods/a_mapgen_mods/mg_villages/fill_chest.lua
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
--[[-- TODO: refill chest after some time?
|
||||||
|
-- TODO: alert NPC that something was taken
|
||||||
|
|
||||||
|
mg_villages.random_chest_content = {};
|
||||||
|
|
||||||
|
-- add random chest content
|
||||||
|
local ADD_RCC = function( data )
|
||||||
|
if( data and #data>3 and ( minetest.registered_nodes[ data[1] ] or minetest.registered_items[ data[1] ]) ) then
|
||||||
|
table.insert( mg_villages.random_chest_content, data );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- things that can be found in private, not locked chests belonging to npc
|
||||||
|
-- contains tables of the following structure: { node_name, probability (in percent, 100=always, 0=never), max_amount, repeat (for more than one stack) }
|
||||||
|
mg_villages.random_chest_content = {};
|
||||||
|
|
||||||
|
ADD_RCC({"default:pick_stone", 10, 1, 3, farm_tiny=1, farm_full=1, shed=1, lumberjack=1, hut=1, chest_work=1, lumberjack=1 });
|
||||||
|
ADD_RCC({"default:pick_steel", 5, 1, 2, forge=1 });
|
||||||
|
ADD_RCC({"default:pick_mese", 2, 1, 2, forge=1, lumberjack=1 });
|
||||||
|
ADD_RCC({"default:shovel_stone", 5, 1, 3, farm_tiny=1, farm_full=1, shed=1, lumberjack=1, hut=1, chest_work=1 });
|
||||||
|
ADD_RCC({"default:shovel_steel", 5, 1, 2, forge=1 });
|
||||||
|
ADD_RCC({"default:axe_stone", 5, 1, 3, farm_tiny=1, farm_full=1, chest_work=1, lumberjack=1 });
|
||||||
|
ADD_RCC({"default:axe_steel", 5, 1, 2, forge=1, lumberjack=1 });
|
||||||
|
ADD_RCC({"default:sword_wood", 1, 1, 3, guard=1 });
|
||||||
|
ADD_RCC({"default:sword_stone", 1, 1, 3, guard=1 });
|
||||||
|
ADD_RCC({"default:sword_steel", 1, 1, 3, forge=1, guard=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"default:stick", 20, 40, 2, church=1, library=1, chest_private=1, shelf=5, shed=1, lumberjack=1, hut=1 });
|
||||||
|
ADD_RCC({"default:torch", 50, 10, 4, church=1, library=1, chest_private=1, shelf=1, shed=1, lumberjack=1, hut=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"default:book", 60, 1, 2, church=1, library=1 });
|
||||||
|
ADD_RCC({"default:paper", 60, 6, 4, church=1, library=1 });
|
||||||
|
ADD_RCC({"default:apple", 50, 10, 2, chest_storage=4, chest_private=1, shelf=5});
|
||||||
|
ADD_RCC({"default:ladder", 20, 1, 2, church=1, library=1, shed=1, lumberjack=1, hut=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"default:coal_lump", 80, 30, 1, forge=1, shed=1, lumberjack=1, hut=1});
|
||||||
|
ADD_RCC({"default:steel_ingot", 30, 4, 2, forge=1 });
|
||||||
|
ADD_RCC({"default:mese_crystal_fragment", 10, 3, 1, forge=1, chest_storage=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"bucket:bucket_empty", 10, 3, 2, chest_work=1, forge=1, shed=1, hut=1 });
|
||||||
|
ADD_RCC({"bucket:bucket_water", 5, 3, 2, chest_work=1, forge=1 });
|
||||||
|
ADD_RCC({"bucket:bucket_lava", 3, 3, 2, forge=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"vessels:glass_bottle", 10, 10, 2, church=1, library=1, shelf=1 });
|
||||||
|
ADD_RCC({"vessels:drinking_glass", 20, 2, 1, church=1, library=1, shelf=1 });
|
||||||
|
ADD_RCC({"vessels:steel_bottle", 10, 1, 1, church=1, library=1, shelf=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"wool:white", 60, 8, 2, church=1, library=1 });
|
||||||
|
|
||||||
|
|
||||||
|
-- that someone will hide valuable ingots in chests that are not locked is fairly unrealistic; thus, those items are rare
|
||||||
|
ADD_RCC({"moreores:gold_ingot", 1, 2, 1 });
|
||||||
|
ADD_RCC({"moreores:silver_ingot", 1, 2, 1 });
|
||||||
|
ADD_RCC({"moreores:copper_ingot", 30, 10, 1 });
|
||||||
|
ADD_RCC({"moreores:tin_ingot", 1, 5, 1 });
|
||||||
|
ADD_RCC({"moreores:bronze_ingot", 1, 1, 1 });
|
||||||
|
ADD_RCC({"moreores:mithril_ingot", 1, 1, 1 });
|
||||||
|
|
||||||
|
-- candles are a very likely content of chests
|
||||||
|
ADD_RCC({"candles:candle", 80, 12, 2, church=1, library=1, chest_private=1 });
|
||||||
|
ADD_RCC({"candles:candelabra_steel", 1, 1, 1, church=1, library=1, chest_private=1 });
|
||||||
|
ADD_RCC({"candles:candelabra_copper", 1, 1, 1, church=1, library=1, chest_private=1 });
|
||||||
|
ADD_RCC({"candles:honey", 50, 2, 1 });
|
||||||
|
|
||||||
|
-- our NPC have to spend their free time somehow...also adds food variety
|
||||||
|
ADD_RCC({"fishing:pole", 60, 1, 1 });
|
||||||
|
|
||||||
|
-- ropes are always useful
|
||||||
|
if( minetest.get_modpath("ropes") ~= nil ) then
|
||||||
|
ADD_RCC({"ropes:rope", 60, 5, 2, chest_work=1, shelf=1, chest_storage=1 });
|
||||||
|
elseif( minetest.get_modpath("farming") ~= nil ) then
|
||||||
|
ADD_RCC({"farming:string", 60, 5, 2, church=1, library=1, chest_work=1, shelf=1, chest_storage=1 });
|
||||||
|
elseif( minetest.get_modpath("moreblocks") ~= nil ) then
|
||||||
|
ADD_RCC({"moreblocks:rope", 60, 5, 2, chest_work=1, shelf=1, chest_storage=1 });
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
ADD_RCC({'bees:bottle_honey', 50, 4, 1, beekeeper=3, tavern=1, inn=1, chest_storage=1 });
|
||||||
|
ADD_RCC({'bees:extractor', 80, 1, 2, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:frame_empty', 50, 2, 5, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:frame_full', 80, 1, 1, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:grafting_tool', 50, 1, 3, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:hive_industrial', 100, 1, 1, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:honey_comb', 50, 2, 2, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:queen_bee', 50, 2, 3, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:smoker', 80, 1, 2, beekeeper=1 });
|
||||||
|
ADD_RCC({'bees:wax', 80, 3, 3, beekeeper=1 });
|
||||||
|
|
||||||
|
ADD_RCC({'bushes:blackberry', 80, 20, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:blackberry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:blueberry', 80, 20, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:blueberry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:gooseberry', 80, 20, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:gooseberry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:raspberry', 80, 20, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:raspberry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:mixed_berry_pie_cooked', 80, 12, 4, bakery=1 });
|
||||||
|
ADD_RCC({'bushes:sugar', 80, 99, 5, bakery=1, shelf=1 });
|
||||||
|
|
||||||
|
ADD_RCC({'carts:cart', 80, 1, 2, miner=1});
|
||||||
|
|
||||||
|
ADD_RCC({'castle:battleaxe', 50, 1, 1, guard=1, forge=1 });
|
||||||
|
ADD_RCC({'castle:ropebox', 50, 2, 2, guard=1 });
|
||||||
|
ADD_RCC({'castle:ropes', 50, 1, 1, guard=2, chest_private=1, chest_work=2 });
|
||||||
|
ADD_RCC({'castle:shield', 50, 1, 1, guard=1 });
|
||||||
|
ADD_RCC({'castle:shield_2', 50, 1, 1, guard=1 });
|
||||||
|
ADD_RCC({'castle:shield_3', 50, 1, 1, guard=1 });
|
||||||
|
|
||||||
|
ADD_RCC({'cottages:anvil', 80, 1, 2, forge=1 });
|
||||||
|
|
||||||
|
ADD_RCC({'currency:minegeld', 80, 10, 2, chest_private=1, chest_work=1 }); -- TODO: could be in any chest with a certain chance
|
||||||
|
|
||||||
|
ADD_RCC({'farming:hoe_stone', 80, 1, 2, farm_tiny=2, farm_full=2, chest_work=2 });
|
||||||
|
|
||||||
|
ADD_RCC({'homedecor:beer_mug', 50, 1, 2, tavern=5, inn=3});
|
||||||
|
ADD_RCC({'homedecor:book_blue', 50, 1, 2, church=1, library=1, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:book_red', 50, 1, 2, church=1, library=1, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:book_green', 50, 1, 2, church=1, library=1, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:bottle_brown', 50, 1, 2, tavern=3, inn=3, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:bottle_green', 50, 1, 2, tavern=3, inn=3, chest_private=1});
|
||||||
|
ADD_RCC({'homedecor:calendar', 50, 1, 1, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1});
|
||||||
|
ADD_RCC({"homedecor:candle", 50, 2, 1, church=2, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
ADD_RCC({"homedecor:candle_thin", 50, 2, 1, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
ADD_RCC({"homedecor:copper_pans", 80, 1, 1, chest_work=1 });
|
||||||
|
ADD_RCC({"homedecor:dardboard", 50, 1, 1, tavern=1});
|
||||||
|
ADD_RCC({"homedecor:oil_extract", 80, 1, 3, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
ADD_RCC({"homedecor:oil_lamp", 50, 2, 1, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
ADD_RCC({"homedecor:torch_wall", 50, 2, 1, church=1, library=1, chest_private=1, chest_work=1, chest_storage=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"locks:key", 50, 2, 1, chest_private=1, chest_work=1, chest_storage=1, forge=1 });
|
||||||
|
ADD_RCC({"locks:keychain", 50, 2, 1, chest_private=1, chest_work=1, chest_storage=1, forge=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"moretrees:coconut_milk", 80, 5, 2, tavern=1, inn=1 });
|
||||||
|
ADD_RCC({"moretrees:raw_coconut", 80, 5, 2, tavern=1, inn=1 });
|
||||||
|
ADD_RCC({"moretrees:pine_nuts", 80, 99, 1, tavern=1, inn=1, chest_storage=3 });
|
||||||
|
ADD_RCC({"moretrees:spruce_nuts", 80, 99, 1, tavern=1, inn=1, chest_storage=3 });
|
||||||
|
|
||||||
|
ADD_RCC({"quartz:quartz_crystal", 80, 1, 1, library=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"screwdriver:screwdriver", 80, 1, 1, chest_work=1 });
|
||||||
|
|
||||||
|
ADD_RCC({"unified_inventory:bag_large", 80, 1, 1, chest_private=1, chest_storage=2 });
|
||||||
|
ADD_RCC({"unified_inventory:bag_medium", 80, 1, 1, chest_private=1, chest_storage=2 });
|
||||||
|
ADD_RCC({"unified_inventory:bag_small", 80, 1, 1, tavern=1, inn=1, chest_work=1, chest_private=1 });
|
||||||
|
|
||||||
|
|
||||||
|
-- get some random content for a chest
|
||||||
|
mg_villages.fill_chest_random = function( pos, pr, building_nr, building_typ )
|
||||||
|
|
||||||
|
local building_data = mg_villages.BUILDINGS[ building_nr.btype ];
|
||||||
|
|
||||||
|
local meta = minetest.env:get_meta( pos );
|
||||||
|
local inv = meta:get_inventory();
|
||||||
|
|
||||||
|
local count = 0;
|
||||||
|
|
||||||
|
local typ = minetest.get_name_from_content_id( pos.typ );
|
||||||
|
if( pos.typ_name ) then
|
||||||
|
typ = pos.typ_name;
|
||||||
|
end
|
||||||
|
if( not( typ ) or (typ ~= 'cottages:shelf' and typ ~= 'cottages:chest_work' and typ ~= 'cottages:chest_storage' and typ ~= 'cottages:chest_private' )) then
|
||||||
|
typ = building_data.typ;
|
||||||
|
else
|
||||||
|
typ = string.sub( typ, 10 );
|
||||||
|
end
|
||||||
|
local typ2 = nil;
|
||||||
|
if( typ == 'cottages:chest_work' and building_data.typ ) then
|
||||||
|
typ2 = building_data.typ;
|
||||||
|
end
|
||||||
|
--print('FILLING chest of type '..tostring( typ )..' and '..tostring( typ2));
|
||||||
|
if( not( typ ) or typ=='' ) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
local inv_size = inv:get_size('main');
|
||||||
|
for i,v in ipairs( mg_villages.random_chest_content ) do
|
||||||
|
|
||||||
|
-- repeat this many times
|
||||||
|
for count=1, v[ 4 ] do
|
||||||
|
|
||||||
|
-- to avoid too many things inside a chest, lower probability
|
||||||
|
if( count<30 -- make sure it does not get too much and there is still room for a new stack
|
||||||
|
and (v[ typ ] or (typ2 and v[ typ2 ]))
|
||||||
|
and inv_size and inv_size > 0 and v[ 2 ] > pr:next( 1, 200 )) then
|
||||||
|
|
||||||
|
--inv:add_item('main', v[ 1 ].." "..tostring( math.random( 1, tonumber(v[ 3 ]) )));
|
||||||
|
-- add itemstack at a random position in the chests inventory
|
||||||
|
inv:set_stack( 'main', pr:next( 1, inv:get_size( 'main' )), v[ 1 ].." "..tostring( pr:next( 1, tonumber(v[ 3 ]) )) );
|
||||||
|
count = count+1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end]]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
--the old code used by Nores mg mapgen
|
||||||
|
for _, n in pairs(village.to_add_data.extranodes) do
|
||||||
|
|
||||||
|
-- minetest.set_node(n.pos, n.node)
|
||||||
|
if n.meta ~= nil then
|
||||||
|
|
||||||
|
|
||||||
|
meta = minetest.get_meta(n.pos)
|
||||||
|
meta:from_table(n.meta)
|
||||||
|
if n.node.name == "default:chest" then
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
local items = inv:get_list("main")
|
||||||
|
for i=1, inv:get_size("main") do
|
||||||
|
inv:set_stack("main", i, ItemStack(""))
|
||||||
|
end
|
||||||
|
local numitems = pr:next(3, 20)
|
||||||
|
for i=1,numitems do
|
||||||
|
local ii = pr:next(1, #items)
|
||||||
|
local prob = items[ii]:get_count() % 2 ^ 8
|
||||||
|
local stacksz = math.floor(items[ii]:get_count() / 2 ^ 8)
|
||||||
|
if pr:next(0, prob) == 0 and stacksz>0 then
|
||||||
|
stk = ItemStack({name=items[ii]:get_name(), count=pr:next(1, stacksz), wear=items[ii]:get_wear(), metadata=items[ii]:get_metadata()})
|
||||||
|
local ind = pr:next(1, inv:get_size("main"))
|
||||||
|
while not inv:get_stack("main",ind):is_empty() do
|
||||||
|
ind = pr:next(1, inv:get_size("main"))
|
||||||
|
end
|
||||||
|
inv:set_stack("main", ind, stk)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--]]
|
||||||
|
--the code that works
|
||||||
|
-- adapted from the Mines mod
|
||||||
|
|
||||||
|
local chest_stuff = {
|
||||||
|
{name="default:apple", max = 3},
|
||||||
|
{name="farming:bread", max = 3},
|
||||||
|
{name="default:steel_ingot", max = 2},
|
||||||
|
{name="default:gold_ingot", max = 2},
|
||||||
|
{name="default:axe_steel", max = 1},
|
||||||
|
--{name="default:emerald", max = 5},
|
||||||
|
{name="default:pick_steel", max = 1},
|
||||||
|
{name="default:shovel_steel", max = 1},
|
||||||
|
{name="default:book", max = 3},
|
||||||
|
{name="default:torch", max = 13},
|
||||||
|
{name="default:stick", max = 7},
|
||||||
|
{name="default:coal_lump", max = 4},
|
||||||
|
{name="bucket:bucket_empty", max = 1},
|
||||||
|
{name="default:ladder", max = 10},
|
||||||
|
{name="default:mese_crystal_fragment", max = 2},
|
||||||
|
{name="vessels:glass_bottle", max = 1},
|
||||||
|
{name="wool:white", max = 11},
|
||||||
|
--{name="carpet:white", max = 11},
|
||||||
|
--{name="quartz:quartz_crystal", max = 5},
|
||||||
|
--{name="shears:shears", max = 1},
|
||||||
|
--{name="crops:melon_seed", max = 18},
|
||||||
|
--{name="mobs:saddle", max = 3},
|
||||||
|
{name="farming:carrot", max = 3},
|
||||||
|
{name="farming:corn", max = 3},
|
||||||
|
{name="farming:melon_slice", max = 3},
|
||||||
|
{name="farming:potato", max = 3},
|
||||||
|
{name="farming:raspberries", max = 3},
|
||||||
|
{name="farming:rhubarb", max = 3},
|
||||||
|
{name="farming:sugar", max = 3},
|
||||||
|
{name="farming:tomato", max = 3},
|
||||||
|
{name="farming:seed_wheat", max = 3},
|
||||||
|
{name="farming:cucumber", max = 3},
|
||||||
|
{name="farming:grapes", max = 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- get some random content for a chest
|
||||||
|
mg_villages.fill_chest_random = function( pos, pr, building_nr, building_typ )
|
||||||
|
local meta = minetest.get_meta( pos )
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
inv:set_size("main", 8*4)
|
||||||
|
for i=0,pr:next(1,6),1 do
|
||||||
|
local stuff = chest_stuff[pr:next(1,#chest_stuff)]
|
||||||
|
local stack = {name=stuff.name, count = pr:next(1,stuff.max)}
|
||||||
|
if not inv:contains_item("main", stack) then
|
||||||
|
inv:set_stack("main", pr:next(1,32), stack)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
234
mods/a_mapgen_mods/mg_villages/highlandpools.lua
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
-- highlandpools 0.1.1 by paramat
|
||||||
|
-- For latest stable Minetest back to 0.4.8
|
||||||
|
-- Depends default
|
||||||
|
-- Licenses: code WTFPL
|
||||||
|
|
||||||
|
-- Parameters
|
||||||
|
|
||||||
|
local YMAX = 33000 -- Maximum altitude for pools
|
||||||
|
local FLOW = 256
|
||||||
|
|
||||||
|
-- Stuff
|
||||||
|
|
||||||
|
highlandpools = {}
|
||||||
|
|
||||||
|
-- Functions
|
||||||
|
|
||||||
|
function highlandpools_remtree(x, y, z, area, data)
|
||||||
|
local c_tree = minetest.get_content_id("default:tree")
|
||||||
|
local c_apple = minetest.get_content_id("default:apple")
|
||||||
|
local c_leaves = minetest.get_content_id("default:leaves")
|
||||||
|
local c_air = minetest.get_content_id("air")
|
||||||
|
for j = 1, 7 do
|
||||||
|
for i = -2, 2 do
|
||||||
|
for k = -2, 2 do
|
||||||
|
local vi = area:index(x+i, y+j, z+k)
|
||||||
|
if data[vi] == c_tree
|
||||||
|
or data[vi] == c_apple
|
||||||
|
or data[vi] == c_leaves then
|
||||||
|
data[vi] = c_air
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for j = 1, 7 do
|
||||||
|
for i = -2, 2 do
|
||||||
|
for k = -2, 2 do
|
||||||
|
local vi = area:index(x+i, y-j, z+k)
|
||||||
|
if data[vi] == c_tree
|
||||||
|
or data[vi] == c_apple
|
||||||
|
or data[vi] == c_leaves then
|
||||||
|
data[vi] = c_air
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- On generated function
|
||||||
|
|
||||||
|
mg_villages.do_highlandpools = function(minp, maxp, seed, vm, area, data, village_area)
|
||||||
|
local y0 = minp.y
|
||||||
|
if y0 < -32 or y0 > YMAX then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local x0 = minp.x
|
||||||
|
local z0 = minp.z
|
||||||
|
local x1 = maxp.x
|
||||||
|
local y1 = maxp.y
|
||||||
|
local z1 = maxp.z
|
||||||
|
local sidelen = x1 - x0 -- actually sidelen - 1
|
||||||
|
|
||||||
|
local c_air = minetest.get_content_id("air")
|
||||||
|
local c_ignore = minetest.get_content_id("ignore")
|
||||||
|
local c_watsour = minetest.get_content_id("default:river_water_source")
|
||||||
|
local c_grass = minetest.get_content_id("default:dirt_with_grass")
|
||||||
|
local c_tree = minetest.get_content_id("default:tree")
|
||||||
|
local c_apple = minetest.get_content_id("default:apple")
|
||||||
|
local c_leaves = minetest.get_content_id("default:leaves")
|
||||||
|
local c_dirt = minetest.get_content_id("default:dirt")
|
||||||
|
|
||||||
|
for xcen = x0 + 8, x1 - 7, 8 do
|
||||||
|
for zcen = z0 + 8, z1 - 7, 8 do
|
||||||
|
-- TODO: village_area[ x ][ z ][ 2 ] == 0 means: not inside any village area or terrain blend area
|
||||||
|
local yasurf = false -- y of above surface node
|
||||||
|
for y = y1, 2, -1 do
|
||||||
|
local vi = area:index(xcen, y, zcen)
|
||||||
|
local c_node = data[vi]
|
||||||
|
if y == y1 and c_node ~= c_air then -- if top node solid
|
||||||
|
break
|
||||||
|
elseif c_node == c_watsour then
|
||||||
|
break
|
||||||
|
elseif c_node == c_grass then
|
||||||
|
yasurf = y + 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if yasurf then
|
||||||
|
local abort = false
|
||||||
|
for ser = 1, 80 do
|
||||||
|
local vi = area:index(xcen + ser, yasurf, zcen)
|
||||||
|
local c_node = data[vi]
|
||||||
|
if xcen + ser == x1 then
|
||||||
|
abort = true
|
||||||
|
elseif c_node ~= c_air
|
||||||
|
and c_node ~= c_tree
|
||||||
|
and c_node ~= c_leaves
|
||||||
|
and c_node ~= c_apple then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for ser = 1, 80 do
|
||||||
|
local vi = area:index(xcen - ser, yasurf, zcen)
|
||||||
|
local c_node = data[vi]
|
||||||
|
if xcen - ser == x0 then
|
||||||
|
abort = true
|
||||||
|
elseif c_node ~= c_air
|
||||||
|
and c_node ~= c_tree
|
||||||
|
and c_node ~= c_leaves
|
||||||
|
and c_node ~= c_apple then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for ser = 1, 80 do
|
||||||
|
local vi = area:index(xcen, yasurf, zcen + ser)
|
||||||
|
local c_node = data[vi]
|
||||||
|
if zcen + ser == z1 then
|
||||||
|
abort = true
|
||||||
|
elseif c_node ~= c_air
|
||||||
|
and c_node ~= c_tree
|
||||||
|
and c_node ~= c_leaves
|
||||||
|
and c_node ~= c_apple then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for ser = 1, 80 do
|
||||||
|
local vi = area:index(xcen, yasurf, zcen - ser)
|
||||||
|
local c_node = data[vi]
|
||||||
|
if zcen - ser == z0 then
|
||||||
|
abort = true
|
||||||
|
elseif c_node ~= c_air
|
||||||
|
and c_node ~= c_tree
|
||||||
|
and c_node ~= c_leaves
|
||||||
|
and c_node ~= c_apple then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if abort then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local vi = area:index(xcen, yasurf, zcen)
|
||||||
|
data[vi] = c_watsour
|
||||||
|
local flab = false -- flow abort
|
||||||
|
for flow = 1, FLOW do
|
||||||
|
for z = z0, z1 do
|
||||||
|
for x = x0, x1 do
|
||||||
|
local vif = area:index(x, yasurf, z)
|
||||||
|
if data[vif] == c_watsour then
|
||||||
|
if x == x0 or x == x1 or z == z0 or z == z1 then
|
||||||
|
flab = true -- if water at chunk edge abort flow
|
||||||
|
break
|
||||||
|
else -- flow water
|
||||||
|
local vie = area:index(x + 1, yasurf, z)
|
||||||
|
local viw = area:index(x - 1, yasurf, z)
|
||||||
|
local vin = area:index(x, yasurf, z + 1)
|
||||||
|
local vis = area:index(x, yasurf, z - 1)
|
||||||
|
if data[vie] == c_tree then
|
||||||
|
highlandpools_remtree(x + 1, yasurf, z, area, data)
|
||||||
|
data[vie] = c_watsour
|
||||||
|
elseif data[vie] == c_air
|
||||||
|
or data[vie] == c_apple
|
||||||
|
or data[vie] == c_leaves then
|
||||||
|
data[vie] = c_watsour
|
||||||
|
end
|
||||||
|
if data[viw] == c_tree then
|
||||||
|
highlandpools_remtree(x - 1, yasurf, z, area, data)
|
||||||
|
data[viw] = c_watsour
|
||||||
|
elseif data[viw] == c_air
|
||||||
|
or data[viw] == c_apple
|
||||||
|
or data[viw] == c_leaves then
|
||||||
|
data[viw] = c_watsour
|
||||||
|
end
|
||||||
|
if data[vin] == c_tree then
|
||||||
|
highlandpools_remtree(x, yasurf, z + 1, area, data)
|
||||||
|
data[vin] = c_watsour
|
||||||
|
elseif data[vin] == c_air
|
||||||
|
or data[vin] == c_apple
|
||||||
|
or data[vin] == c_leaves then
|
||||||
|
data[vin] = c_watsour
|
||||||
|
end
|
||||||
|
if data[vis] == c_tree then
|
||||||
|
highlandpools_remtree(x, yasurf, z - 1, area, data)
|
||||||
|
data[vis] = c_watsour
|
||||||
|
elseif data[vis] == c_air
|
||||||
|
or data[vis] == c_apple
|
||||||
|
or data[vis] == c_leaves then
|
||||||
|
data[vis] = c_watsour
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if flab then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if flab then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if flab then -- erase water from this y level
|
||||||
|
for z = z0, z1 do
|
||||||
|
for x = x0, x1 do
|
||||||
|
local vi = area:index(x, yasurf, z)
|
||||||
|
if data[vi] == c_watsour then
|
||||||
|
data[vi] = c_air
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else -- flow downwards add dirt
|
||||||
|
for z = z0, z1 do
|
||||||
|
for x = x0, x1 do
|
||||||
|
local vi = area:index(x, yasurf, z)
|
||||||
|
if data[vi] == c_watsour then
|
||||||
|
for y = yasurf - 1, y0, -1 do
|
||||||
|
local viu = area:index(x, y, z)
|
||||||
|
if data[viu] == c_air then
|
||||||
|
data[viu] = c_watsour
|
||||||
|
elseif data[viu] == c_grass then
|
||||||
|
data[viu] = c_dirt
|
||||||
|
break
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
75
mods/a_mapgen_mods/mg_villages/init.lua
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
-- reserve namespace for the villages
|
||||||
|
mg_villages = {}
|
||||||
|
|
||||||
|
mg_villages.all_villages = {}
|
||||||
|
mg_villages.mg_generated_map = {}
|
||||||
|
mg_villages.anz_villages = 0;
|
||||||
|
|
||||||
|
mg_villages.modpath = minetest.get_modpath( "mg_villages");
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.DEBUG_LEVEL_NONE = -1 -- -1: disable all printed messages
|
||||||
|
mg_villages.DEBUG_LEVEL_NORMAL = 0 -- 0: print information about which village spawned where plus important errors
|
||||||
|
mg_villages.DEBUG_LEVEL_WARNING = 1 -- 1: warnings/errors which may not be particulary helpful for non-developers
|
||||||
|
mg_villages.DEBUG_LEVEL_INFO = 2 -- 2: print even less important warnings
|
||||||
|
mg_villages.DEBUG_LEVEL_TIMING = 3 -- 3: detailled performance information
|
||||||
|
|
||||||
|
mg_villages.print = function( level, msg )
|
||||||
|
if( level <= mg_villages.DEBUG_LEVEL ) then
|
||||||
|
print( "[mg_villages] "..msg );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- save_restore is now part of handle_schematics
|
||||||
|
--dofile(mg_villages.modpath.."/save_restore.lua")
|
||||||
|
mg_villages.all_villages = save_restore.restore_data( 'mg_all_villages.data' ); -- read mg_villages.all_villages data saved for this world from previous runs
|
||||||
|
mg_villages.mg_generated_map = save_restore.restore_data( 'mg_generated_map.data' );
|
||||||
|
|
||||||
|
dofile(mg_villages.modpath.."/config.lua")
|
||||||
|
|
||||||
|
-- adds a special gravel node which will neither fall nor be griefed by mapgen
|
||||||
|
dofile(mg_villages.modpath.."/nodes.lua")
|
||||||
|
|
||||||
|
-- the default game no longer provides helpful tree growing code
|
||||||
|
dofile(mg_villages.modpath.."/trees.lua")
|
||||||
|
|
||||||
|
dofile(mg_villages.modpath.."/replacements.lua")
|
||||||
|
|
||||||
|
-- multiple diffrent village types with their own sets of houses are supported
|
||||||
|
-- The function mg_villages.add_village_type( village_type_name, village_type_data )
|
||||||
|
-- allows other mods to add new village types.
|
||||||
|
dofile(mg_villages.modpath.."/village_types.lua")
|
||||||
|
|
||||||
|
-- Note: the "buildings" talbe is not in the mg_villages.* namespace
|
||||||
|
-- The function mg_villages.add_building( building_data ) allows other mods to add buildings.
|
||||||
|
dofile(mg_villages.modpath.."/buildings.lua")
|
||||||
|
|
||||||
|
-- mg_villages.init_weights() has to be called AFTER all village types and buildings have
|
||||||
|
-- been added using the functions above
|
||||||
|
dofile(mg_villages.modpath.."/init_weights.lua")
|
||||||
|
|
||||||
|
-- generate village names
|
||||||
|
dofile(mg_villages.modpath.."/name_gen.lua");
|
||||||
|
|
||||||
|
dofile(mg_villages.modpath.."/villages.lua")
|
||||||
|
|
||||||
|
-- adds a command that allows to teleport to a known village
|
||||||
|
dofile(mg_villages.modpath.."/chat_commands.lua")
|
||||||
|
-- protect villages from griefing
|
||||||
|
dofile(mg_villages.modpath.."/protection.lua")
|
||||||
|
-- create and show a map of the world
|
||||||
|
dofile(mg_villages.modpath.."/map_of_world.lua")
|
||||||
|
|
||||||
|
dofile(mg_villages.modpath.."/fill_chest.lua")
|
||||||
|
|
||||||
|
-- terrain blending for individual houses
|
||||||
|
dofile(mg_villages.modpath.."/terrain_blend.lua")
|
||||||
|
-- highlandpools
|
||||||
|
dofile(mg_villages.modpath.."/highlandpools.lua")
|
||||||
|
-- the interface for the mapgen;
|
||||||
|
-- also takes care of spawning the player
|
||||||
|
dofile(mg_villages.modpath.."/mapgen.lua")
|
||||||
|
|
||||||
|
dofile(mg_villages.modpath.."/spawn_player.lua")
|
43
mods/a_mapgen_mods/mg_villages/init_weights.lua
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
-- this functions needs to be called once after *all* village types and buildings have been added
|
||||||
|
mg_villages.init_weights = function()
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
mg_villages.print(mg_villages.DEBUG_LEVEL_NORMAL,'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';
|
||||||
|
for j,v in ipairs( mg_villages.village_types ) do
|
||||||
|
|
||||||
|
local total_weight = 0
|
||||||
|
for _, i in ipairs(mg_villages.BUILDINGS) do
|
||||||
|
if( not( i.max_weight )) then
|
||||||
|
i.max_weight = {};
|
||||||
|
end
|
||||||
|
if( i.weight and i.weight[ v ] and i.weight[ v ]>0 ) then
|
||||||
|
total_weight = total_weight+i.weight[ v ]
|
||||||
|
i.max_weight[v] = total_weight
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local multiplier = 3000/total_weight
|
||||||
|
for _,i in ipairs(mg_villages.BUILDINGS) do
|
||||||
|
if( i.weight and i.weight[ v ] and i.weight[ v ]>0 ) then
|
||||||
|
i.max_weight[v] = i.max_weight[ v ]*multiplier
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- the fields do not exist as an independent type
|
||||||
|
mg_villages.village_types[ #mg_villages.village_types ] = nil;
|
||||||
|
-- neither does the tower type
|
||||||
|
mg_villages.village_types[ #mg_villages.village_types ] = nil;
|
||||||
|
-- and neither does the "single" type (==lone houses outside villages)
|
||||||
|
mg_villages.village_types[ #mg_villages.village_types ] = nil;
|
||||||
|
end
|
193
mods/a_mapgen_mods/mg_villages/map_of_world.lua
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
|
||||||
|
|
||||||
|
-- villages up to this many nodes in each direction are shown on the map
|
||||||
|
mg_villages.MAP_RANGE = 1000;
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.draw_tile = function( content_id, image, x, z, dx, dz, tile_nr )
|
||||||
|
if( not( image )) then
|
||||||
|
local node_name = minetest.get_name_from_content_id( content_id );
|
||||||
|
if( not( node_name )) then
|
||||||
|
return '';
|
||||||
|
end
|
||||||
|
local node_def = minetest.registered_nodes[ node_name ];
|
||||||
|
if( not( node_def )) then
|
||||||
|
return '';
|
||||||
|
end
|
||||||
|
local tiles = node_def.tiles;
|
||||||
|
local tile = nil;
|
||||||
|
if( tiles ~= nil ) then
|
||||||
|
if( not(tile_nr) or tile_nr > #tiles or tile_nr < 1 ) then
|
||||||
|
tile_nr = 1;
|
||||||
|
end
|
||||||
|
tile = tiles[tile_nr];
|
||||||
|
end
|
||||||
|
if type(tile)=="table" then
|
||||||
|
tile=tile["name"]
|
||||||
|
end
|
||||||
|
image = tile;
|
||||||
|
if( not( image )) then
|
||||||
|
image = "unknown_object.png";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return "image["..tostring(x)..",".. tostring(z) ..";"..dx..','..dz..";" .. image .."]";
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.map_of_world = function( pname )
|
||||||
|
|
||||||
|
local player = minetest.get_player_by_name( pname );
|
||||||
|
if( not( player )) then
|
||||||
|
return '';
|
||||||
|
end
|
||||||
|
local ppos = player:getpos();
|
||||||
|
|
||||||
|
-- also usable: diamond_block, sand, water
|
||||||
|
local formspec = "size[14.4,10]"..
|
||||||
|
"background[0,0;10,10;"..mg_villages.MAP_BACKGROUND_IMAGE.."]"..
|
||||||
|
"label[10,10;x axis]"..
|
||||||
|
"label[0,0;z axis]"..
|
||||||
|
"label[0,10;|]"..
|
||||||
|
"label[0.2,10;->]";
|
||||||
|
|
||||||
|
|
||||||
|
local r = mg_villages.MAP_RANGE;
|
||||||
|
local f1 = 10/(2*r);
|
||||||
|
|
||||||
|
local map_tiles_shown = math.floor( mg_villages.MAP_RANGE/80 );
|
||||||
|
local center_x = math.floor( ppos.x/80 );
|
||||||
|
local center_z = math.floor( ppos.z/80 );
|
||||||
|
for x = center_x - map_tiles_shown, center_x + map_tiles_shown do
|
||||||
|
for z = center_z - map_tiles_shown, center_z + map_tiles_shown do
|
||||||
|
if( mg_villages.mg_generated_map[ x ] and mg_villages.mg_generated_map[ x ][ z ] ) then
|
||||||
|
local surface_types = mg_villages.mg_generated_map[ x ][ z ];
|
||||||
|
local content_id = 0;
|
||||||
|
if( type( surface_types )=='table' ) then
|
||||||
|
content_id = surface_types[ 26 ];
|
||||||
|
else
|
||||||
|
content_id = surface_types;
|
||||||
|
end
|
||||||
|
|
||||||
|
local x1 = f1 * ((x*80) - ppos.x +r);
|
||||||
|
local z1 = f1 * ( (2*r) - ((z*80) - ppos.z + r));
|
||||||
|
local dx = f1 * 80;
|
||||||
|
local dz = f1 * 80;
|
||||||
|
|
||||||
|
formspec = formspec..mg_villages.draw_tile( content_id, nil, x1+0.5, z1-0.5, dx*1.25, dz*1.25, 1 );
|
||||||
|
|
||||||
|
-- if more detailed information is available, draw those tiles that differ from the most common tile
|
||||||
|
if( type( surface_types )=='table' and false) then -- TODO: disabled for now
|
||||||
|
dx = dx/5;
|
||||||
|
dz = dz/5;
|
||||||
|
for i,v in ipairs( surface_types ) do
|
||||||
|
if( v ~= content_id ) then
|
||||||
|
local x2 = x1+( math.floor( (i-1)/5 )*dx);
|
||||||
|
local z2 = z1+( math.floor( (i-1)%5 )*dz);
|
||||||
|
formspec = formspec..mg_villages.draw_tile( v, nil, x2+0.5, z2-0.5, dx*1.3, dz*1.3, 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local shown_villages = {};
|
||||||
|
|
||||||
|
r = mg_villages.MAP_RANGE;
|
||||||
|
f1 = 10/(2*r);
|
||||||
|
for name,v in pairs( mg_villages.all_villages ) do
|
||||||
|
|
||||||
|
local data = v; --minetest.deserialize( v );
|
||||||
|
local x = data.vx - ppos.x;
|
||||||
|
local z = data.vz - ppos.z;
|
||||||
|
|
||||||
|
-- show only villages which are at max mg_villages.MAP_RANGE away from player
|
||||||
|
if( x and z
|
||||||
|
and mg_villages.village_type_data[ data.village_type ]
|
||||||
|
and mg_villages.village_type_data[ data.village_type ].texture
|
||||||
|
and math.abs( x ) < r
|
||||||
|
and math.abs( z ) < r ) then
|
||||||
|
|
||||||
|
-- the village size determines the texture size
|
||||||
|
local dx = f1 * (data.vs*2) *1.25;
|
||||||
|
local dz = f1 * (data.vs*2) *1.0;
|
||||||
|
|
||||||
|
-- center the village texture
|
||||||
|
x = x - (data.vs/2);
|
||||||
|
z = z + (data.vs/2);
|
||||||
|
|
||||||
|
-- calculate the position for the village texture
|
||||||
|
x = f1 * (x+r);
|
||||||
|
z = f1 * ( (2*r) -(z+r));
|
||||||
|
|
||||||
|
formspec = formspec..
|
||||||
|
"label["..x..",".. z ..";"..tostring( data.nr ).."]"..mg_villages.draw_tile( nil, mg_villages.village_type_data[ data.village_type ].texture, x, z, dx, dz, 1 );
|
||||||
|
|
||||||
|
shown_villages[ #shown_villages+1 ] = tostring( data.nr )..". "..tostring( v.name or 'unknown' ).."]";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- code and arrows taken from mapp mod
|
||||||
|
local yaw = player:get_look_yaw()
|
||||||
|
local rotate = 0;
|
||||||
|
if yaw ~= nil then
|
||||||
|
-- Find rotation and texture based on yaw.
|
||||||
|
yaw = math.deg(yaw)
|
||||||
|
yaw = math.fmod (yaw, 360)
|
||||||
|
if yaw<0 then yaw = 360 + yaw end
|
||||||
|
if yaw>360 then yaw = yaw - 360 end
|
||||||
|
if yaw < 90 then
|
||||||
|
rotate = 90
|
||||||
|
elseif yaw < 180 then
|
||||||
|
rotate = 180
|
||||||
|
elseif yaw < 270 then
|
||||||
|
rotate = 270
|
||||||
|
else
|
||||||
|
rotate = 0
|
||||||
|
end
|
||||||
|
yaw = math.fmod(yaw, 90)
|
||||||
|
yaw = math.floor(yaw / 10) * 10
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- show the players yaw
|
||||||
|
if rotate ~= 0 then
|
||||||
|
formspec = formspec.."image[".. 4.95 ..",".. 4.85 ..";0.4,0.4;d" .. yaw .. ".png^[transformFYR".. rotate .."]"
|
||||||
|
else
|
||||||
|
formspec = formspec.."image[".. 4.95 ..",".. 4.85 ..";0.4,0.4;d" .. yaw .. ".png^[transformFY]"
|
||||||
|
end
|
||||||
|
|
||||||
|
local i = 0.05;
|
||||||
|
formspec = formspec.."label[10,-0.4;Village types:]";
|
||||||
|
-- explain the meaning of the textures
|
||||||
|
if mg_villages.village_types ~= nil then
|
||||||
|
for _,typ in ipairs(mg_villages.village_types) do
|
||||||
|
formspec = formspec.."label[10.5,"..tostring(i)..";"..tostring( typ ).."]"..
|
||||||
|
"image[10.0,"..tostring(i+0.1)..";0.4,0.4;"..tostring( mg_villages.village_type_data[ typ ].texture ).."]";
|
||||||
|
i = i+0.45;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
i = i+0.45;
|
||||||
|
formspec = formspec.."label[10.0,"..tostring(i)..";Villages shown on this map:]";
|
||||||
|
i = i+0.45;
|
||||||
|
local j = 1;
|
||||||
|
while (i<10.5 and j<=#shown_villages) do
|
||||||
|
|
||||||
|
formspec = formspec.."label[10.0,"..tostring(i)..";"..tostring( shown_villages[ j ] ).."]";
|
||||||
|
i = i+0.45;
|
||||||
|
j = j+1;
|
||||||
|
end
|
||||||
|
|
||||||
|
return formspec;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_chatcommand( 'vmap', {
|
||||||
|
description = "Shows a map of all known villages withhin "..tostring( mg_villages.MAP_RANGE ).." blocks.",
|
||||||
|
privs = {},
|
||||||
|
func = function(name, param)
|
||||||
|
minetest.show_formspec( name, 'mg:world_map', mg_villages.map_of_world( name ));
|
||||||
|
end
|
||||||
|
});
|
||||||
|
|
1215
mods/a_mapgen_mods/mg_villages/mapgen.lua
Normal file
90
mods/a_mapgen_mods/mg_villages/name_gen.lua
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
|
||||||
|
namegen = {};
|
||||||
|
|
||||||
|
namegen.prefixes = {'ac','ast','lang','pen','shep','ship'}
|
||||||
|
namegen.suffixes = {'beck','ey','ay','bury','burgh','brough','by','by','caster',
|
||||||
|
'cester','cum','den','don','field','firth','ford','ham','ham','ham',
|
||||||
|
'hope','ing','kirk','hill','law','leigh','mouth','ness','pool','shaw',
|
||||||
|
'stead','ster','tun','ton','ton','ton','ton','wold','worth','worthy',
|
||||||
|
'ville','river','forrest','lake'}
|
||||||
|
|
||||||
|
-- people/environmental features
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namegen.silben = { 'a', 'an', 'ab', 'ac', 'am',
|
||||||
|
'be', 'ba', 'bi', 'bl', 'bm', 'bn', 'bo', 'br', 'bst', 'bu',
|
||||||
|
'ca', 'ce', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'cv',
|
||||||
|
'da', 'de', 'df', 'di', 'dl', 'dm', 'dn', 'do', 'dr', 'ds', 'dt', 'du', 'dv',
|
||||||
|
'do','ren','nav','ben','ada','min','org','san','pa','re','ne','en','er','ich',
|
||||||
|
'the','and','tha','ent','ing','ion','tio','for','nde',
|
||||||
|
'has','nce','edt','tis','oft','sth','mem',
|
||||||
|
'ich','ein','und','der','nde','sch','die','den','end','cht',
|
||||||
|
'the','and','tha','ent','ing','ion','for','de',
|
||||||
|
'has','ce','ed','is','ft','sth','mem',
|
||||||
|
'ch','ei','un','der','ie','den','end',
|
||||||
|
'do','ren','nav','ben','ada','min','org','san','pa','re','ne','en','er','ich',
|
||||||
|
'ta','bek','nik','le','lan','nem',
|
||||||
|
'bal','cir','da','en','fan','fir','fern','fa','oak','nut','gen','ga','hu','hi','hal',
|
||||||
|
'in','ig','ir','im','ja','je','jo','kla','kon','ker','log','lag','leg','lil',
|
||||||
|
'lon','las','leve','lere','mes','mir','mon','mm','mer','mig',
|
||||||
|
'na','nn','nerv','neu','oto','on','opt','oll','ome','ott',
|
||||||
|
'pen','par','pi','pa','po','pel','pig','qu','ren','rig','raf','res','ring',
|
||||||
|
'rib','rast','rost','ru','rum','rem','sem','sim','su','spring',
|
||||||
|
'cotton','cot','wood','palm',
|
||||||
|
'do','na','ik','ke','gen','bra','bn','lla','lle','st','aa','kir',
|
||||||
|
'nn','en','fo','fn','gi','ja','jn','ke','kr','kon','lis','on','ok','or','op',
|
||||||
|
'pp','p','qu','re','ra','rn','ri','so','sn','se','ti','tu',
|
||||||
|
'a','e','i','o','u',
|
||||||
|
're','ro','pe','pn','ci','co','cl',
|
||||||
|
'no','en','wi','we','er','en','ba','ki','nn','va','wu','x','tel','or',
|
||||||
|
'so','me','mi','em','en','eg','ge','kn'};
|
||||||
|
|
||||||
|
|
||||||
|
namegen.generate_village_name = function( pr )
|
||||||
|
local anz_silben = pr:next(2,5);
|
||||||
|
local name = '';
|
||||||
|
local prefix = '';
|
||||||
|
local postfix = '';
|
||||||
|
if( pr:next(1,8)==1) then
|
||||||
|
prefix = namegen.prefixes[ #namegen.prefixes ];
|
||||||
|
anz_silben = anz_silben -1;
|
||||||
|
end
|
||||||
|
if( pr:next(1,4)==1) then
|
||||||
|
postfix = name..namegen.suffixes[ #namegen.suffixes ];
|
||||||
|
anz_silben = anz_silben -2;
|
||||||
|
end
|
||||||
|
if( anz_silben < 2 ) then
|
||||||
|
anz_silben = 2;
|
||||||
|
end
|
||||||
|
for i = 1, anz_silben do
|
||||||
|
name = name..namegen.silben[ pr:next( 1, #namegen.silben )];
|
||||||
|
end
|
||||||
|
name = prefix..name..postfix;
|
||||||
|
name = string.upper( string.sub( name, 1, 1 ) )..string.sub( name, 2 );
|
||||||
|
return name;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
namegen.generate_village_name_with_prefix = function( pr, village )
|
||||||
|
|
||||||
|
local name = namegen.generate_village_name( pr );
|
||||||
|
|
||||||
|
-- if a village consists of a single house, it gets a prefix depending on the house type
|
||||||
|
if( village.is_single_house and village.to_add_data and village.to_add_data.bpos ) then
|
||||||
|
-- the building got removed from mg_villages.BUILDINGS in the meantime
|
||||||
|
if( not( mg_villages.BUILDINGS[ village.to_add_data.bpos[1].btype] )) then
|
||||||
|
return 'Abandomed building';
|
||||||
|
end
|
||||||
|
local btyp = mg_villages.BUILDINGS[ village.to_add_data.bpos[1].btype].typ;
|
||||||
|
local bdata = mg_villages.village_type_data[ btyp ];
|
||||||
|
if( bdata and (bdata.name_prefix or bdata.name_postfix )) then
|
||||||
|
name = (bdata.name_prefix or '')..name..(bdata.name_postfix or '');
|
||||||
|
else
|
||||||
|
name = 'House '..name;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return name;
|
||||||
|
end
|
142
mods/a_mapgen_mods/mg_villages/nodes.lua
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
|
||||||
|
minetest.register_node("mg_villages:road", {
|
||||||
|
description = "village road",
|
||||||
|
tiles = {"default_gravel.png", "default_dirt.png"},
|
||||||
|
is_ground_content = true, -- will be removed by the cave generator
|
||||||
|
groups = {crumbly=2, falling_node = 1}, -- does fall
|
||||||
|
sounds = default.node_sound_dirt_defaults({
|
||||||
|
footstep = {name="default_gravel_footstep", gain=0.5},
|
||||||
|
dug = {name="default_gravel_footstep", gain=1.0},
|
||||||
|
}),
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = { { -0.5, -0.5, -0.5, 0.5, 0.5-2/16, 0.5}, },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
mg_villages.road_node = minetest.get_content_id( 'mg_villages:road' );
|
||||||
|
-- do not drop snow on roads
|
||||||
|
if( moresnow ) then
|
||||||
|
moresnow.snow_cover[ mg_villages.road_node ] = moresnow.c_air;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_node("mg_villages:soil", {
|
||||||
|
description = "Soil found on a field",
|
||||||
|
tiles = {"es_mud.png^farming_soil_wet.png", "es_mud.png"},
|
||||||
|
drop = "es:mud",
|
||||||
|
is_ground_content = true,
|
||||||
|
groups = {crumbly=3, not_in_creative_inventory=1, grassland = 1},
|
||||||
|
sounds = default.node_sound_dirt_defaults(),
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node("mg_villages:desert_sand_soil", {
|
||||||
|
description = "Desert Sand",
|
||||||
|
tiles = {"default_desert_sand.png^farming_soil_wet.png", "default_desert_sand.png"},
|
||||||
|
is_ground_content = true,
|
||||||
|
drop = "default:desert_sand",
|
||||||
|
groups = {crumbly=3, not_in_creative_inventory = 1, sand=1, desert = 1},
|
||||||
|
sounds = default.node_sound_sand_defaults(),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
-- This torch is not hot. It will not melt snow and cause no floodings in villages.
|
||||||
|
minetest.register_node("mg_villages:torch", {
|
||||||
|
description = "Torch-air",
|
||||||
|
drawtype = "torchlike",
|
||||||
|
--tiles = {"default_torch_on_floor.png", "default_torch_on_ceiling.png", "default_torch.png"},
|
||||||
|
tiles = {"default_invis.png"},
|
||||||
|
inventory_image = "default_torch_on_floor.png",
|
||||||
|
wield_image = "default_torch_on_floor.png",
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "wallmounted",
|
||||||
|
sunlight_propagates = true,
|
||||||
|
is_ground_content = false,
|
||||||
|
walkable = false,
|
||||||
|
--light_source = LIGHT_MAX-1,
|
||||||
|
selection_box = {
|
||||||
|
type = "wallmounted",
|
||||||
|
wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1},
|
||||||
|
wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1},
|
||||||
|
wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1},
|
||||||
|
},
|
||||||
|
groups = {choppy=2,dig_immediate=3,flammable=1,attached_node=1},
|
||||||
|
legacy_wallmounted = true,
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
|
drop = "default:torch",
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_node("mg_villages:plotmarker", {
|
||||||
|
description = "Plot marker",
|
||||||
|
drawtype = "nodebox",
|
||||||
|
tiles = {"default_stone_brick.png"},
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{-0.5+2/16, -0.5, -0.5+2/16, 0.5-2/16, -0.5+3/16, 0.5-2/16},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
groups = {cracky=3,stone=2},
|
||||||
|
|
||||||
|
on_rightclick = function( pos, node, clicker, itemstack, pointed_thing)
|
||||||
|
return mg_villages.plotmarker_formspec( pos, nil, {}, clicker )
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_receive_fields = function(pos, formname, fields, sender)
|
||||||
|
return mg_villages.plotmarker_formspec( pos, formname, fields, sender );
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- protect against digging
|
||||||
|
can_dig = function( pos, player )
|
||||||
|
local meta = minetest.get_meta( pos );
|
||||||
|
if( meta and meta:get_string( 'village_id' )~='' and meta:get_int( 'plot_nr' ) and meta:get_int( 'plot_nr' )>0) then
|
||||||
|
return false;
|
||||||
|
end
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
-- default to safe lava
|
||||||
|
if( not( mg_villages.use_normal_unsafe_lava )) then
|
||||||
|
local lava = minetest.registered_nodes[ "default:lava_source"];
|
||||||
|
if( lava ) then
|
||||||
|
-- a deep copy for the table would be more helpful...but, well, ...
|
||||||
|
local new_def = minetest.deserialize( minetest.serialize( lava ));
|
||||||
|
-- this lava does not cause fire to spread
|
||||||
|
new_def.name = nil;
|
||||||
|
new_def.groups.lava = nil;
|
||||||
|
new_def.groups.hot = nil;
|
||||||
|
new_def.groups.igniter = nil;
|
||||||
|
new_def.groups.lava_tamed = 3;
|
||||||
|
new_def.description = "Lava Source (tame)";
|
||||||
|
new_def.liquid_alternative_flowing = "mg_villages:lava_flowing_tamed";
|
||||||
|
new_def.liquid_alternative_source = "mg_villages:lava_source_tamed";
|
||||||
|
-- we create a NEW type of lava for this
|
||||||
|
minetest.register_node( "mg_villages:lava_source_tamed", new_def );
|
||||||
|
end
|
||||||
|
|
||||||
|
-- take care of the flowing variant as well
|
||||||
|
lava = minetest.registered_nodes[ "default:lava_flowing"];
|
||||||
|
if( lava ) then
|
||||||
|
-- a deep copy for the table would be more helpful...but, well, ...
|
||||||
|
local new_def = minetest.deserialize( minetest.serialize( lava ));
|
||||||
|
-- this lava does not cause fire to spread
|
||||||
|
new_def.name = nil;
|
||||||
|
new_def.groups.lava = nil;
|
||||||
|
new_def.groups.hot = nil;
|
||||||
|
new_def.groups.igniter = nil;
|
||||||
|
new_def.groups.lava_tamed = 3;
|
||||||
|
new_def.description = "Flowing Lava (tame)";
|
||||||
|
new_def.liquid_alternative_flowing = "mg_villages:lava_flowing_tamed";
|
||||||
|
new_def.liquid_alternative_source = "mg_villages:lava_source_tamed";
|
||||||
|
-- and a NEW type of flowing lava...
|
||||||
|
minetest.register_node( "mg_villages:lava_flowing_tamed", new_def );
|
||||||
|
end
|
||||||
|
end
|
307
mods/a_mapgen_mods/mg_villages/protection.lua
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
-- get the id of the village pos lies in (or nil if outside of villages)
|
||||||
|
mg_villages.get_town_id_at_pos = function( pos )
|
||||||
|
for id, v in pairs( mg_villages.all_villages ) do
|
||||||
|
local size = v.vs * 3;
|
||||||
|
if( ( math.abs( pos.x - v.vx ) < size )
|
||||||
|
and ( math.abs( pos.z - v.vz ) < size )
|
||||||
|
and ( pos.y - v.vh < 40 and v.vh - pos.y < 10 )) then
|
||||||
|
local village_noise = minetest.get_perlin(7635, 3, 0.5, 16);
|
||||||
|
if( mg_villages.inside_village_area( pos.x, pos.z, v, village_noise)) then
|
||||||
|
|
||||||
|
local node = minetest.get_node( pos );
|
||||||
|
-- leaves can be digged in villages
|
||||||
|
if( node and node.name ) then
|
||||||
|
if( minetest.registered_nodes[ node.name ]
|
||||||
|
and minetest.registered_nodes[ node.name ].groups
|
||||||
|
and minetest.registered_nodes[ node.name ].groups.leaves ) then
|
||||||
|
return nil;
|
||||||
|
elseif( node.name=='default:snow' ) then
|
||||||
|
return nil;
|
||||||
|
-- bones can be digged in villages
|
||||||
|
elseif( node.name == 'bones:bones' ) then
|
||||||
|
return nil;
|
||||||
|
else
|
||||||
|
return id;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return id;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
|
||||||
|
local old_is_protected = minetest.is_protected
|
||||||
|
minetest.is_protected = function(pos, name)
|
||||||
|
|
||||||
|
if( not( mg_villages.ENABLE_PROTECTION )) then
|
||||||
|
return old_is_protected( pos, name );
|
||||||
|
end
|
||||||
|
|
||||||
|
local village_id = mg_villages.get_town_id_at_pos( pos );
|
||||||
|
if( village_id ) then
|
||||||
|
local is_houseowner = false;
|
||||||
|
for nr, p in ipairs( mg_villages.all_villages[ village_id ].to_add_data.bpos ) do
|
||||||
|
|
||||||
|
trustedusers = p.can_edit
|
||||||
|
trustedUser = false
|
||||||
|
if trustedusers ~= nil then
|
||||||
|
for _,trusted in ipairs(trustedusers) do
|
||||||
|
if trusted == name then
|
||||||
|
trustedUser = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we have located the right plot; the player can build here if he owns this particular plot
|
||||||
|
if( p.x <= pos.x and (p.x + p.bsizex) >= pos.x
|
||||||
|
and p.z <= pos.z and (p.z + p.bsizez) >= pos.z) then
|
||||||
|
|
||||||
|
-- If player has been trusted by owner, can build
|
||||||
|
if (trustedUser) then
|
||||||
|
return false;
|
||||||
|
-- If player is owner, can build
|
||||||
|
elseif( p.owner and p.owner == name ) then
|
||||||
|
return false;
|
||||||
|
-- the allmende can be used by all
|
||||||
|
elseif( mg_villages.BUILDINGS[p.btype] and mg_villages.BUILDINGS[p.btype].typ=="allmende" ) then
|
||||||
|
return false;
|
||||||
|
-- the player cannot modify other plots, even though he may be house owner of another house and be allowed to modify common ground
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
-- if the player just owns another plot in the village, check if it's one where villagers may live
|
||||||
|
elseif( p.owner and p.owner == name or trustedUser) then
|
||||||
|
local btype = mg_villages.all_villages[ village_id ].to_add_data.bpos[ nr ].btype;
|
||||||
|
if( btype ~= 'road'
|
||||||
|
and mg_villages.BUILDINGS[btype]
|
||||||
|
and mg_villages.BUILDINGS[btype].inh
|
||||||
|
and mg_villages.BUILDINGS[btype].inh > 0 ) then
|
||||||
|
is_houseowner = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- players who own a house in town where villagers may live (not only work!)
|
||||||
|
-- are allowed to modify common ground
|
||||||
|
if( is_houseowner ) then
|
||||||
|
return false;
|
||||||
|
end
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
return old_is_protected(pos, name);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_on_protection_violation( function(pos, name)
|
||||||
|
|
||||||
|
if( not( mg_villages.ENABLE_PROTECTION )) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local found = mg_villages.get_town_id_at_pos( pos );
|
||||||
|
if( not( found ) or not( mg_villages.all_villages[ found ])) then
|
||||||
|
minetest.chat_send_player( name, 'Error: This area does not belong to a village.');
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.chat_send_player( name, "You are inside of the area of the village "..
|
||||||
|
tostring( mg_villages.all_villages[ found ].name )..
|
||||||
|
". The inhabitants do not allow you any modifications.");
|
||||||
|
end );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.plotmarker_formspec = function( pos, formname, fields, player )
|
||||||
|
|
||||||
|
-- if( not( mg_villages.ENABLE_PROTECTION )) then
|
||||||
|
-- return;
|
||||||
|
-- end
|
||||||
|
local meta = minetest.get_meta( pos );
|
||||||
|
if( not( meta )) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
local village_id = meta:get_string('village_id');
|
||||||
|
local plot_nr = meta:get_int( 'plot_nr');
|
||||||
|
local pname = player:get_player_name();
|
||||||
|
|
||||||
|
if( not( village_id )
|
||||||
|
or not( mg_villages.all_villages )
|
||||||
|
or not( mg_villages.all_villages[ village_id ] )
|
||||||
|
or not( plot_nr )
|
||||||
|
or not( mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ] )) then
|
||||||
|
minetest.chat_send_player( pname, 'Error. This plot marker is not configured correctly.'..minetest.serialize({village_id,plot_nr }));
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local owner = mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].owner;
|
||||||
|
local btype = mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].btype;
|
||||||
|
|
||||||
|
--minetest.chat_send_player( player:get_player_name(),'DATA FOR '..tostring(plot_nr)..': '..minetest.serialize( mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ] ));
|
||||||
|
local original_formspec = "size[8,3]"..
|
||||||
|
"label[1.0,0.5;Plot No.: "..tostring( plot_nr ).."]"..
|
||||||
|
"label[2.5,0.5;Building:]"..
|
||||||
|
"label[3.5,0.5;"..tostring( mg_villages.BUILDINGS[btype].scm ).."]"..
|
||||||
|
"field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]";
|
||||||
|
local formspec = "";
|
||||||
|
local ifinhabit = "";
|
||||||
|
|
||||||
|
-- Get Price
|
||||||
|
local price = "default:gold_ingot 2";
|
||||||
|
|
||||||
|
if (btype ~= 'road' and mg_villages.BUILDINGS[btype]) then
|
||||||
|
local plot_descr = 'Plot No. '..tostring( plot_nr ).. ' with '..tostring( mg_villages.BUILDINGS[btype].scm)
|
||||||
|
|
||||||
|
if (mg_villages.BUILDINGS[btype].price) then
|
||||||
|
price = mg_villages.BUILDINGS[btype].price;
|
||||||
|
elseif (mg_villages.BUILDINGS[btype].typ and mg_villages.prices[ mg_villages.BUILDINGS[btype].typ ]) then
|
||||||
|
price = mg_villages.prices[ mg_villages.BUILDINGS[btype].typ ];
|
||||||
|
end
|
||||||
|
-- Get if is inhabitant house
|
||||||
|
if (mg_villages.BUILDINGS[btype].inh and mg_villages.BUILDINGS[btype].inh > 0 ) then
|
||||||
|
ifinhabit = "label[1,1.5;Owners of this plot count as village inhabitants.]";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Determine price depending on building type
|
||||||
|
local price_stack= ItemStack( price );
|
||||||
|
|
||||||
|
|
||||||
|
-- If nobody owns the plot
|
||||||
|
if (not(owner) or owner=='') then
|
||||||
|
|
||||||
|
formspec = original_formspec ..
|
||||||
|
"label[1,1;You can buy this plot for]"..
|
||||||
|
"label[3.8,1;"..tostring( price_stack:get_count() ).." x ]"..
|
||||||
|
"item_image[4.3,0.8;1,1;"..( price_stack:get_name() ).."]"..
|
||||||
|
ifinhabit..
|
||||||
|
"button[2,2.5;1.5,0.5;buy;Buy plot]"..
|
||||||
|
"button_exit[4,2.5;1.5,0.5;abort;Exit]";
|
||||||
|
|
||||||
|
-- On Press buy button
|
||||||
|
if (fields['buy']) then
|
||||||
|
local inv = player:get_inventory();
|
||||||
|
|
||||||
|
if not mg_villages.all_villages[village_id].ownerlist then
|
||||||
|
mg_villages.all_villages[village_id].ownerlist = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if player already has a house in the village
|
||||||
|
if mg_villages.all_villages[village_id].ownerlist[pname] then
|
||||||
|
formspec = formspec.."label[1,1.9;Sorry. You already have a plot in this village.]";
|
||||||
|
|
||||||
|
-- Check if the price can be paid
|
||||||
|
elseif( inv and inv:contains_item( 'main', price_stack )) then
|
||||||
|
formspec = original_formspec..
|
||||||
|
"label[1,1;Congratulations! You have bought this plot.]"..
|
||||||
|
"button_exit[5.75,2.5;1.5,0.5;abort;Exit]";
|
||||||
|
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].owner = pname;
|
||||||
|
if mg_villages.all_villages[village_id].ownerlist then
|
||||||
|
mg_villages.all_villages[village_id].ownerlist[pname] = true;
|
||||||
|
else
|
||||||
|
mg_villages.all_villages[village_id].ownerlist[pname] = true;
|
||||||
|
end
|
||||||
|
meta:set_string('infotext', 'Plot No. '..tostring( plot_nr ).. ' with '..tostring( mg_villages.BUILDINGS[btype].scm)..' (owned by '..tostring( pname )..')');
|
||||||
|
-- save the data so that it survives server restart
|
||||||
|
mg_villages.save_data();
|
||||||
|
-- substract the price from the players inventory
|
||||||
|
inv:remove_item( 'main', price_stack );
|
||||||
|
else
|
||||||
|
formspec = formspec.."label[1,1.9;Sorry. You are not able to pay the price.]";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If player is the owner of the plot
|
||||||
|
elseif (owner==pname) then
|
||||||
|
|
||||||
|
-- Check if inhabitant house
|
||||||
|
if(btype ~= 'road'
|
||||||
|
and mg_villages.BUILDINGS[btype]
|
||||||
|
and mg_villages.BUILDINGS[btype].inh
|
||||||
|
and mg_villages.BUILDINGS[btype].inh > 0 ) then
|
||||||
|
|
||||||
|
ifinhabit = "label[1,1.5;You are allowed to modify the common village area.]";
|
||||||
|
end
|
||||||
|
|
||||||
|
formspec = original_formspec.."size[8,3]"..
|
||||||
|
"label[1,1;This is your plot. You have bought it.]"..
|
||||||
|
"button[0.75,2.5;3,0.5;add_remove;Add/Remove Players]"..
|
||||||
|
ifinhabit..
|
||||||
|
"button_exit[3.75,2.5;2.0,0.5;abandon;Abandon plot]"..
|
||||||
|
"button_exit[5.75,2.5;1.5,0.5;abort;Exit]";
|
||||||
|
|
||||||
|
-- If Player wants to abandon plot
|
||||||
|
if(fields['abandon'] ) then
|
||||||
|
formspec = original_formspec..
|
||||||
|
"label[1,1;You have abandoned this plot.]"..
|
||||||
|
"button_exit[5.75,2.5;1.5,0.5;abort;Exit]";
|
||||||
|
mg_villages.all_villages[village_id].ownerlist[pname] = nil;
|
||||||
|
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit = {}
|
||||||
|
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].owner = nil;
|
||||||
|
-- Return price to player
|
||||||
|
local inv = player:get_inventory();
|
||||||
|
inv:add_item( 'main', price_stack );
|
||||||
|
meta:set_string('infotext', 'Plot No. '..tostring( plot_nr ).. ' with '..tostring( mg_villages.BUILDINGS[btype].scm) );
|
||||||
|
mg_villages.save_data();
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If Player wants to add/remove trusted players
|
||||||
|
if (fields['add_remove']) then
|
||||||
|
local previousTrustees = mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit
|
||||||
|
local output = "";
|
||||||
|
if previousTrustees == nil then
|
||||||
|
previousTrustees = {}
|
||||||
|
else
|
||||||
|
for _, player in ipairs(previousTrustees) do
|
||||||
|
output = output..player.."\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
formspec = "size[8,3]"..
|
||||||
|
"field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]"..
|
||||||
|
"textarea[0.3,0.2;8,2.5;ownerplayers;Trusted Players;"..output.."]"..
|
||||||
|
"button[3.25,2.5;1.5,0.5;savetrustees;Save]";
|
||||||
|
|
||||||
|
mg_villages.save_data()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save trusted players
|
||||||
|
if (fields["savetrustees"] == "Save") then
|
||||||
|
|
||||||
|
if not mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit then
|
||||||
|
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local x = 1;
|
||||||
|
for _, player in ipairs(fields.ownerplayers:split("\n")) do
|
||||||
|
mg_villages.all_villages[ village_id ].to_add_data.bpos[ plot_nr ].can_edit[x] = player
|
||||||
|
x = x + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
mg_villages.save_data();
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If A different Player owns plot
|
||||||
|
else
|
||||||
|
formspec = original_formspec.."label[1,1;"..tostring( owner ).." owns this plot.]"..
|
||||||
|
"button_exit[3,2.5;1.5,0.5;abort;Exit]";
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.show_formspec( pname, "mg_villages:plotmarker", formspec );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.form_input_handler = function( player, formname, fields)
|
||||||
|
-- mg_villages.print(mg_villages.DEBUG_LEVEL_NORMAL,minetest.serialize(fields));
|
||||||
|
if( not( mg_villages.ENABLE_PROTECTION )) then
|
||||||
|
return false;
|
||||||
|
end
|
||||||
|
if( (formname == "mg_villages:plotmarker") and fields.pos2str and not( fields.abort )) then
|
||||||
|
local pos = minetest.string_to_pos( fields.pos2str );
|
||||||
|
mg_villages.plotmarker_formspec( pos, formname, fields, player );
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
return false;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_on_player_receive_fields( mg_villages.form_input_handler )
|
964
mods/a_mapgen_mods/mg_villages/replacements.lua
Normal file
@ -0,0 +1,964 @@
|
|||||||
|
|
||||||
|
-- ethereal comes with some intresting trees
|
||||||
|
if( minetest.get_modpath( 'ethereal' )) then
|
||||||
|
mg_villages.ethereal_trees = {'acacia','willow','redwood','frost','mushroom','yellow','palm','banana'};
|
||||||
|
end
|
||||||
|
|
||||||
|
if( minetest.get_modpath( 'forest' )) then
|
||||||
|
mg_villages.forest_trees = {'beech','birch','cherry','fir','ginkgo','lavender','mirabelle','oak','plum','willow'};
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we are dealing with the TinyTrees mod from Bas080
|
||||||
|
if( minetest.get_modpath( 'trees' )
|
||||||
|
and minetest.registered_nodes[ 'trees:wood_mangrove' ] ) then
|
||||||
|
mg_villages.tinytrees_trees = {'mangrove','palm','conifer'};
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The trees modname is not unique; there are other mods which bear that name.
|
||||||
|
-- If all the other mods are present as well, it's a strong indication for realtest beeing the game.
|
||||||
|
if( minetest.get_modpath( 'trees' )
|
||||||
|
and minetest.get_modpath( 'anvil')
|
||||||
|
and minetest.get_modpath( 'joiner_table')
|
||||||
|
and minetest.get_modpath( 'scribing_table' )) then
|
||||||
|
mg_villages.realtest_trees = {'ash','aspen','birch','maple','chestnut','pine','spruce'};
|
||||||
|
--print('REALTEST trees will be used.'); else print( 'NO REALTEST trees');
|
||||||
|
|
||||||
|
-- realtest is very special as far as stairs are concerned
|
||||||
|
mg_villages.realtest_stairs = {'default:stone','default:stone_flat','default:stone_bricks',
|
||||||
|
'default:desert_stone_flat','default:desert_stone_bricks'};
|
||||||
|
for i,v in ipairs(metals.list) do
|
||||||
|
table.insert( mg_villages.realtest_stairs, 'metals:'..v..'_block' );
|
||||||
|
end
|
||||||
|
-- the list of minteral names is local; so we can't add "decorations:"..mineral[1].."_block"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- only the function mg_villages.get_replacement_table(..) is called from outside this file
|
||||||
|
|
||||||
|
mg_villages.replace_materials = function( replacements, pr, original_materials, prefixes, materials, old_material )
|
||||||
|
|
||||||
|
local postfixes = {};
|
||||||
|
local use_realtest_stairs = false;
|
||||||
|
-- handle realtest stairs/slabs
|
||||||
|
if( mg_villages.realtest_trees
|
||||||
|
and #prefixes==3
|
||||||
|
and prefixes[1]=='stairs:stair_' and prefixes[2]=='stairs:slab_' and prefixes[3]=='default:' ) then
|
||||||
|
|
||||||
|
prefixes = {''};
|
||||||
|
materials = mg_villages.realtest_stairs;
|
||||||
|
postfixes = {''};
|
||||||
|
use_realtest_stairs = true;
|
||||||
|
|
||||||
|
elseif( mg_villages.realtest_trees
|
||||||
|
and #prefixes==1
|
||||||
|
and prefixes[1]=='stairs:stair_') then
|
||||||
|
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
for i,v in ipairs( prefixes ) do
|
||||||
|
postfixes[i] = '';
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local known_materials = {};
|
||||||
|
local wood_found = false;
|
||||||
|
-- for all alternate materials
|
||||||
|
for i,m in ipairs( materials ) do
|
||||||
|
-- check if that material exists for each supplied prefix
|
||||||
|
for j,p in ipairs( prefixes ) do
|
||||||
|
-- if wood is present, later on try moretrees wood as well
|
||||||
|
if( 'default:wood' == m ) then
|
||||||
|
wood_found = true;
|
||||||
|
end
|
||||||
|
if( minetest.registered_nodes[ p..m..postfixes[j] ] ) then
|
||||||
|
table.insert( known_materials, m..postfixes[j] );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- support wooden planks from moretrees
|
||||||
|
if( wood_found and mg_villages.moretrees_treelist ) then
|
||||||
|
for _,v in ipairs( mg_villages.moretrees_treelist ) do
|
||||||
|
if( minetest.registered_nodes[ "moretrees:"..v[1].."_planks"] ) then
|
||||||
|
table.insert( known_materials, "moretrees:"..v[1].."_planks" );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
-- deco is used by BigFreakingDig; as that one lacks default nodes, it doesn't work out here
|
||||||
|
if( wood_found and minetest.get_modpath('deco')) then
|
||||||
|
local bfd_treelist = {'birch', 'cherry', 'evergreen', 'oak' };
|
||||||
|
for _,v in ipairs( bfd_treelist ) do
|
||||||
|
if( minetest.registered_nodes[ "deco:"..v.."_plank"] ) then
|
||||||
|
table.insert( known_materials, "deco:"..v.."_plank" );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
|
if( wood_found and mg_villages.ethereal_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.ethereal_trees ) do
|
||||||
|
-- mushroom in ethereal is a pretty decorative material; increase its probability
|
||||||
|
if( v == 'mushroom' ) then
|
||||||
|
table.insert( known_materials, "ethereal:mushroom_pore" );
|
||||||
|
table.insert( known_materials, "ethereal:mushroom_pore" );
|
||||||
|
table.insert( known_materials, "ethereal:mushroom_pore" );
|
||||||
|
-- also increase probability for the decorative blueish wood
|
||||||
|
table.insert( known_materials, "ethereal:frost_wood" );
|
||||||
|
table.insert( known_materials, "ethereal:frost_wood" );
|
||||||
|
elseif( minetest.registered_nodes[ "ethereal:"..v.."_wood"] ) then
|
||||||
|
table.insert( known_materials, "ethereal:"..v.."_wood" );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if( wood_found and mg_villages.forest_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.forest_trees ) do
|
||||||
|
if( minetest.registered_nodes[ 'forest:'..v..'_wood'] ) then
|
||||||
|
table.insert( known_materials, 'forest:'..v..'_wood' );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if( wood_found and mg_villages.tinytrees_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.tinytrees_trees ) do
|
||||||
|
if( minetest.registered_nodes[ 'trees:wood_'..v] ) then
|
||||||
|
table.insert( known_materials, 'trees:wood_'..v );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if( wood_found and mg_villages.realtest_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.realtest_trees ) do
|
||||||
|
if( minetest.registered_nodes[ 'trees:'..v..'_planks'] ) then
|
||||||
|
table.insert( known_materials, 'trees:'..v..'_planks' );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- nothing found which could be used
|
||||||
|
if( #known_materials < 1 ) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
local new_material = known_materials[ pr:next( 1, #known_materials )];
|
||||||
|
|
||||||
|
if( use_realtest_stairs == true ) then
|
||||||
|
table.insert( replacements, { original_materials[ 1 ], new_material..'_stair' } );
|
||||||
|
table.insert( replacements, { original_materials[ 2 ], new_material..'_slab' } );
|
||||||
|
table.insert( replacements, { original_materials[ 3 ], new_material } );
|
||||||
|
table.insert( replacements, { original_materials[ 1 ]..'upside_down', new_material..'_stair_upside_down' } );
|
||||||
|
table.insert( replacements, { original_materials[ 2 ]..'upside_down', new_material..'_slab_upside_down' } );
|
||||||
|
return new_material;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- no replacement necessary if we did choose the same material as before
|
||||||
|
if( new_material == old_material or old_material == (prefixes[1]..new_material)) then
|
||||||
|
return old_material;
|
||||||
|
end
|
||||||
|
|
||||||
|
for i,v in ipairs( prefixes ) do
|
||||||
|
table.insert( replacements, { original_materials[ i ], v..new_material } );
|
||||||
|
end
|
||||||
|
return new_material;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- replace the tree trunk as well so that it fits to the wood type
|
||||||
|
mg_villages.replace_tree_trunk = function( replacements, wood_type )
|
||||||
|
if( wood_type == 'default:junglewood' ) then
|
||||||
|
table.insert( replacements, {'default:tree', 'default:jungletree'});
|
||||||
|
elseif( wood_type == 'default:pine_wood' ) then
|
||||||
|
table.insert( replacements, {'default:tree', 'default:pine_tree'});
|
||||||
|
elseif( wood_type == 'default:acacia_wood' ) then
|
||||||
|
table.insert( replacements, {'default:tree', 'default:acacia_tree'});
|
||||||
|
elseif( wood_type == 'mg:savannawood' ) then
|
||||||
|
table.insert( replacements, {'default:tree', 'mg:savannatree'});
|
||||||
|
elseif( wood_type == 'mg:pinewood' ) then
|
||||||
|
table.insert( replacements, {'default:tree', 'mg:pinetree'});
|
||||||
|
|
||||||
|
elseif( mg_villages.moretrees_treelist ) then
|
||||||
|
for _,v in ipairs( mg_villages.moretrees_treelist ) do
|
||||||
|
if( wood_type == "moretrees:"..v[1].."_planks" ) then
|
||||||
|
table.insert( replacements, {'default:tree', "moretrees:"..v[1].."_trunk"});
|
||||||
|
table.insert( replacements, {'default:leaves', "moretrees:"..v[1].."_leaves"});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( wood_type == 'deco:birch_plank' ) then
|
||||||
|
table.insert( replacements, {'default:tree', "mapgen:birch_log"});
|
||||||
|
elseif( wood_type == 'deco:cherry_plank' ) then
|
||||||
|
table.insert( replacements, {'default:tree', "mapgen:cherry_log"});
|
||||||
|
elseif( wood_type == 'deco:evergreen_plank' ) then
|
||||||
|
table.insert( replacements, {'default:tree', "mapgen:evergreen_log"});
|
||||||
|
elseif( wood_type == 'deco:oak_plank' ) then
|
||||||
|
table.insert( replacements, {'default:tree', "mapgen:oak_log"});
|
||||||
|
|
||||||
|
elseif( wood_type == 'ethereal:frost_wood' ) then
|
||||||
|
table.insert( replacements, {'default:tree', "ethereal:frost_tree"});
|
||||||
|
|
||||||
|
elseif( wood_type == "ethereal:mushroom_pore" ) then
|
||||||
|
table.insert( replacements, {'default:tree', "ethereal:mushroom_trunk"});
|
||||||
|
|
||||||
|
elseif( mg_villages.ethereal_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.ethereal_trees ) do
|
||||||
|
if( wood_type == "ethereal:"..v.."_wood" ) then
|
||||||
|
table.insert( replacements, {'default:tree', "ethereal:"..v.."_trunk"});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( mg_villages.forest_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.forest_trees ) do
|
||||||
|
if( wood_type == "forest:"..v.."_wood" ) then
|
||||||
|
table.insert( replacements, {'default:tree', "forest:"..v.."_tree"});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( mg_villages.tinytrees_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.tinytrees_trees ) do
|
||||||
|
if( wood_type == "trees:wood_"..v ) then
|
||||||
|
table.insert( replacements, {'default:tree', "trees:tree_"..v});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( mg_villages.realtest_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.realtest_trees ) do
|
||||||
|
if( wood_type == 'trees:'..v..'_planks' ) then
|
||||||
|
table.insert( replacements, {'default:tree', "trees:"..v..'_log'});
|
||||||
|
-- realtest does not have most of the nodes from default, so we need to replace them as well
|
||||||
|
table.insert( replacements, {'default:wood', 'trees:'..v..'_planks'});
|
||||||
|
table.insert( replacements, {'default:leaves', 'trees:'..v..'_leaves'});
|
||||||
|
table.insert( replacements, {'default:ladder', 'trees:'..v..'_ladder'});
|
||||||
|
table.insert( replacements, {'default:chest', 'trees:'..v..'_chest'});
|
||||||
|
table.insert( replacements, {'default:chest_locked', 'trees:'..v..'_chest_locked'});
|
||||||
|
table.insert( replacements, {'default:fence_wood', 'fences:'..v..'_fence'});
|
||||||
|
table.insert( replacements, {'default:bookshelf', 'decorations:bookshelf_'..v});
|
||||||
|
table.insert( replacements, {'doors:door_wood_t_1', 'doors:door_'..v..'_t_1'});
|
||||||
|
table.insert( replacements, {'doors:door_wood_b_1', 'doors:door_'..v..'_b_1'});
|
||||||
|
table.insert( replacements, {'doors:door_wood_t_2', 'doors:door_'..v..'_t_2'});
|
||||||
|
table.insert( replacements, {'doors:door_wood_b_2', 'doors:door_'..v..'_b_2'});
|
||||||
|
-- not really wood-realted, but needs to be replaced as well
|
||||||
|
table.insert( replacements, {'default:furnace', 'oven:oven'});
|
||||||
|
-- farming is also handled diffrently
|
||||||
|
table.insert( replacements, {'farming:soil_wet', 'farming:soil'});
|
||||||
|
table.insert( replacements, {'farming:cotton_1', 'farming:flax_1'});
|
||||||
|
table.insert( replacements, {'farming:cotton_2', 'farming:flax_1'});
|
||||||
|
table.insert( replacements, {'farming:cotton_3', 'farming:flax_2'});
|
||||||
|
table.insert( replacements, {'farming:cotton_4', 'farming:flax_2'});
|
||||||
|
table.insert( replacements, {'farming:cotton_5', 'farming:flax_3'});
|
||||||
|
table.insert( replacements, {'farming:cotton_6', 'farming:flax_3'});
|
||||||
|
table.insert( replacements, {'farming:cotton_7', 'farming:flax_4'});
|
||||||
|
table.insert( replacements, {'farming:cotton_8', 'farming:flax_4'});
|
||||||
|
-- stairs and slabs made out of default wood
|
||||||
|
table.insert( replacements, {'stairs:stair_wood', 'trees:'..v..'_planks_stair'});
|
||||||
|
table.insert( replacements, {'stairs:slab_wood', 'trees:'..v..'_planks_slab'});
|
||||||
|
table.insert( replacements, {'stairs:stair_woodupside_down','trees:'..v..'_planks_stair_upside_down' } );
|
||||||
|
table.insert( replacements, {'stairs:slab_woodupside_down', 'trees:'..v..'_planks_slab_upside_down' } );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil;
|
||||||
|
end
|
||||||
|
return wood_type;
|
||||||
|
-- TODO if minetest.get_modpath("moreblocks") and moretrees.enable_stairsplus the
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- if buildings are made out of a certain wood type, people might expect trees of that type nearby
|
||||||
|
mg_villages.replace_saplings = function( replacements, wood_type )
|
||||||
|
if( wood_type == 'default:junglewood' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', 'default:junglesapling'});
|
||||||
|
elseif( wood_type == 'default:pine_wood' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', 'default:pine_sapling'});
|
||||||
|
elseif( wood_type == 'default:acacia_wood' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', 'default:acacia_sapling'});
|
||||||
|
elseif( wood_type == 'mg:savannawood' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', 'mg:savannasapling'});
|
||||||
|
elseif( wood_type == 'mg:pinewood' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', 'mg:pinesapling'});
|
||||||
|
elseif( mg_villages.moretrees_treelist ) then
|
||||||
|
for _,v in ipairs( mg_villages.moretrees_treelist ) do
|
||||||
|
if( wood_type == "moretrees:"..v[1].."_planks" ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "moretrees:"..v[1].."_sapling_ongen"});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif( mg_villages.ethereal_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.ethereal_trees ) do
|
||||||
|
if( wood_type == "ethereal:"..v.."_wood" ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "ethereal:"..v.."_sapling"});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( mg_villages.forest_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.forest_trees ) do
|
||||||
|
if( wood_type == "forest:"..v.."_wood" ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "forest:"..v.."_sapling"});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( mg_villages.tinytrees_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.tinytrees_trees ) do
|
||||||
|
if( wood_type == "trees:wood_"..v ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "trees:sapling_"..v});
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
elseif( mg_villages.realtest_trees ) then
|
||||||
|
for _,v in ipairs( mg_villages.realtest_trees ) do
|
||||||
|
if( wood_type == 'trees:'..v..'_planks' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "trees:"..v.."_sapling"});
|
||||||
|
table.insert( replacements, {'default:junglesapling', "trees:"..v.."_sapling"});
|
||||||
|
table.insert( replacements, {'default:pine_sapling', "trees:"..v.."_sapling"});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif( wood_type == 'deco:birch_plank' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "mapgen:birch_sapling"});
|
||||||
|
elseif( wood_type == 'deco:cherry_plank' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "mapgen:cherry_sapling"});
|
||||||
|
elseif( wood_type == 'deco:evergreen_plank' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "mapgen:evergreen_sapling"});
|
||||||
|
elseif( wood_type == 'deco:oak_plank' ) then
|
||||||
|
table.insert( replacements, {'default:sapling', "mapgen:oak_sapling"});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Note: This function is taken from the villages mod (by Sokomine)
|
||||||
|
-- at least the cottages may come in a variety of building materials
|
||||||
|
-- IMPORTANT: don't add any nodes which have on_construct here UNLESS they where in the original file already
|
||||||
|
-- on_construct will only be called for known nodes that need that treatment (see villages.analyze_mts_file and on_constr)
|
||||||
|
mg_villages.get_replacement_list = function( housetype, pr )
|
||||||
|
|
||||||
|
local replacements = {};
|
||||||
|
|
||||||
|
-- else some grass would never (re)grow (if it's below a roof)
|
||||||
|
-- table.insert( replacements, {'default:dirt', dirt_with_grass_replacement });
|
||||||
|
-- table.insert( replacements, {'default:dirt_with_grass', dirt_with_grass_replacement });
|
||||||
|
table.insert( replacements, {'default:dirt', 'default:dirt_with_grass' });
|
||||||
|
|
||||||
|
-- realtest lacks quite a lot from default
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
for i=1,8 do
|
||||||
|
table.insert( replacements, {'farming:wheat_'..i, 'farming:spelt_'..tostring( (i+(i%2))/2) });
|
||||||
|
table.insert( replacements, {'farming:cotton_'..i, 'farming:flax_' ..tostring( (i+(i%2))/2) });
|
||||||
|
end
|
||||||
|
for i=1,5 do
|
||||||
|
table.insert( replacements, {'default:grass_'..i, 'air' });
|
||||||
|
end
|
||||||
|
table.insert( replacements, {'default:apple', 'air' });
|
||||||
|
table.insert( replacements, {'default:cobble', 'default:stone_macadam' });
|
||||||
|
table.insert( replacements, {'default:obsidian_glass', 'default:glass' });
|
||||||
|
end
|
||||||
|
|
||||||
|
if( housetype and mg_villages.village_type_data[ housetype ] and mg_villages.village_type_data[ housetype ].replacement_function ) then
|
||||||
|
return mg_villages.village_type_data[ housetype ].replacement_function( housetype, pr, replacements );
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Taokis houses from structure i/o
|
||||||
|
mg_villages.replacements_taoki = function( housetype, pr, replacements )
|
||||||
|
local wood_type = 'default:wood';
|
||||||
|
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{'default:wood'},
|
||||||
|
'default:wood');
|
||||||
|
table.insert( replacements, {'stairs:stair_cobble', 'default:stone_bricks_stair' });
|
||||||
|
table.insert( replacements, {'stairs:slab_cobble', 'default:stone_bricks_slab' });
|
||||||
|
table.insert( replacements, {'stairs:stair_stone', 'default:stone_flat_stair' });
|
||||||
|
table.insert( replacements, {'stairs:slab_stone', 'default:stone_flat_slab' });
|
||||||
|
else
|
||||||
|
-- the main body of the houses in the .mts files is made out of wood
|
||||||
|
wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{'default:wood', 'default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'mg:pinewood', 'mg:savannawood',
|
||||||
|
'default:clay', 'default:brick', 'default:sandstone',
|
||||||
|
'default:stonebrick', 'default:desert_stonebrick','default:sandstonebrick', 'default:sandstone','default:stone','default:desert_stone',
|
||||||
|
'default:coalblock','default:steelblock','default:goldblock', 'default:bronzeblock', 'default:copperblock', 'wool:white',
|
||||||
|
'default:stone_flat', 'default:desert_stone_flat', -- realtest
|
||||||
|
'darkage:adobe', 'darkage:basalt', 'darkage:basalt_cobble', 'darkage:chalk',
|
||||||
|
'darkage:gneiss', 'darkage:gneiss_cobble', 'darkage:marble', 'darkage:marble_tile',
|
||||||
|
'darkage:mud', 'darkage:ors', 'darkage:ors_cobble',
|
||||||
|
'darkage:schist', 'darkage:serpentine', 'darkage:shale', 'darkage:silt', 'darkage:slate',
|
||||||
|
'mapgen:mese_stone', 'mapgen:soap_stone'},
|
||||||
|
'default:wood');
|
||||||
|
end
|
||||||
|
-- tree trunks are seldom used in these houses; let's change them anyway
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
|
||||||
|
-- all this comes in variants for stairs and slabs as well
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_stonebrick', 'stairs:slab_stonebrick', 'default:stonebrick'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{ 'stonebrick', 'stone', 'sandstone', 'cobble'},
|
||||||
|
'stonebrick');
|
||||||
|
|
||||||
|
-- decorative slabs above doors etc.
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_wood'},
|
||||||
|
{'stairs:stair_'},
|
||||||
|
{'stonebrick', 'stone', 'sandstone', 'cobble', 'wood', 'junglewood', 'pine_wood', 'acaica_wood' },
|
||||||
|
'wood');
|
||||||
|
|
||||||
|
-- brick roofs are a bit odd; but then...
|
||||||
|
-- all three shapes of roof parts have to fit together
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_brick', 'stairs:slab_brick', 'default:brick'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{ 'brick', 'stone', 'cobble', 'stonebrick', 'wood', 'junglewood', 'pine_wood', 'acacia_wood', 'sandstone' },
|
||||||
|
'brick' );
|
||||||
|
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_nore = function( housetype, pr, replacements )
|
||||||
|
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
-- {'default:stonebrick'},
|
||||||
|
-- {'default:'},
|
||||||
|
{'stairs:stair_stonebrick', 'stairs:slab_stonebrick', 'default:stonebrick'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{'stonebrick', 'desert_stonebrick','sandstonebrick', 'sandstone','stone','desert_stone','stone_flat','desert_stone_flat','stone_bricks','desert_strone_bricks'},
|
||||||
|
'stonebrick');
|
||||||
|
|
||||||
|
-- replace the wood as well
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood', 'default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'mg:savannawood', 'mg:pinewood' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
|
||||||
|
if( pr:next(1,3)==1 and not( mg_villages.realtest_trees)) then
|
||||||
|
table.insert( replacements, {'default:glass', 'default:obsidian_glass'});
|
||||||
|
end
|
||||||
|
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
table.insert( replacements, {'stairs:stair_cobble', 'default:stone_bricks_stair' });
|
||||||
|
table.insert( replacements, {'stairs:slab_cobble', 'default:stone_bricks_slab' });
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_lumberjack = function( housetype, pr, replacements )
|
||||||
|
-- replace the wood - those are lumberjacks after all
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood', 'default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'mg:savannawood', 'mg:pinewood' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
|
||||||
|
if( not( minetest.get_modpath('bell' ))) then
|
||||||
|
table.insert( replacements, {'bell:bell', 'default:goldblock' });
|
||||||
|
end
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
table.insert( replacements, {'stairs:stair_cobble', 'default:stone_bricks_stair' });
|
||||||
|
table.insert( replacements, {'stairs:slab_cobble', 'default:stone_bricks_slab' });
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_logcabin = function( housetype, pr, replacements )
|
||||||
|
|
||||||
|
-- for logcabins, wood is the most likely type of roof material
|
||||||
|
local roof_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_cobble', 'stairs:slab_cobble' },
|
||||||
|
{'cottages:roof_connector_', 'cottages:roof_flat_' },
|
||||||
|
{'straw', 'wood', 'wood', 'wood', 'reet', 'slate', 'red', 'brown', 'black'},
|
||||||
|
'' );
|
||||||
|
-- some houses have junglewood roofs
|
||||||
|
if( roof_type ) then
|
||||||
|
table.insert( replacements, {'stairs:stair_junglewood', 'cottages:roof_connector_'..roof_type });
|
||||||
|
table.insert( replacements, {'stairs:slab_junglewood', 'cottages:roof_flat_'..roof_type });
|
||||||
|
table.insert( replacements, {'cottages:roof_connector_wood', 'cottages:roof_connector_'..roof_type });
|
||||||
|
table.insert( replacements, {'cottages:roof_flat_wood', 'cottages:roof_flat_'..roof_type });
|
||||||
|
-- realtest does not have normal stairs
|
||||||
|
elseif( mg_villages.realtest_trees ) then
|
||||||
|
table.insert( replacements, {'stairs:stair_junglewood', 'trees:aspen_planks_stair' });
|
||||||
|
table.insert( replacements, {'stairs:slab_junglewood', 'trees:aspen_planks_slab' });
|
||||||
|
end
|
||||||
|
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
table.insert( replacements, {'default:stonebrick', 'default:stone_bricks' }); -- used for chimneys
|
||||||
|
table.insert( replacements, {'stairs:stair_stonebrick', 'default:stone_bricks_stair' });
|
||||||
|
-- table.insert( replacements, {'default:junglewood', wood_type }); -- replace the floor
|
||||||
|
-- replace the floor with another type of wood (looks better than the same type as above)
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:junglewood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood' },
|
||||||
|
'default:junglewood');
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_chateau = function( housetype, pr, replacements )
|
||||||
|
|
||||||
|
if( minetest.get_modpath( 'cottages' )) then
|
||||||
|
-- straw is the most likely building material for roofs for historical buildings
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
-- all three shapes of roof parts have to fit together
|
||||||
|
{ 'cottages:roof_straw', 'cottages:roof_connector_straw', 'cottages:roof_flat_straw' },
|
||||||
|
{ 'cottages:roof_', 'cottages:roof_connector_', 'cottages:roof_flat_'},
|
||||||
|
{'straw', 'straw', 'straw', 'straw', 'straw',
|
||||||
|
'reet', 'reet', 'reet',
|
||||||
|
'slate', 'slate',
|
||||||
|
'wood', 'wood',
|
||||||
|
'red',
|
||||||
|
'brown',
|
||||||
|
'black'},
|
||||||
|
'straw');
|
||||||
|
else
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
-- all three shapes of roof parts have to fit together
|
||||||
|
{ 'cottages:roof_straw', 'cottages:roof_connector_straw', 'cottages:roof_flat_straw' },
|
||||||
|
{ 'stairs:stair_', 'stairs:stair_', 'stairs:slab_'},
|
||||||
|
{'cobble', 'stonebrick', 'desert_cobble', 'desert_stonebrick', 'stone'},
|
||||||
|
'stonebrick');
|
||||||
|
table.insert( replacements, { 'cottages:glass_pane', 'default:glass' });
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood', 'default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'mg:savannawood', 'mg:pinewood'}, --, 'default:brick', 'default:sandstone', 'default:desert_cobble' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
|
||||||
|
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
-- replace the floor with another type of wood (looks better than the same type as above)
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_junglewood', 'stairs:slab_junglewood', 'default:junglewood'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{ 'default:wood' },
|
||||||
|
'wood' );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local mfs2 = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_cobble', 'stairs:slab_cobble', 'default:cobble'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{ 'cobble', 'brick', 'clay', 'desert_cobble', 'desert_stone', 'desert_stonebrick', 'loam', 'sandstone', 'sandstonebrick', 'stonebrick' },
|
||||||
|
'cobble');
|
||||||
|
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_tent = function( housetype, pr, replacements )
|
||||||
|
table.insert( replacements, { "glasspanes:wool_pane", "cottages:wool_tent" });
|
||||||
|
table.insert( replacements, { "default:gravel", "default:sand" });
|
||||||
|
-- realtest needs diffrent fence posts and doors
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_grasshut = function( housetype, pr, replacements )
|
||||||
|
table.insert( replacements, {'moreblocks:fence_jungle_wood', 'default:fence' });
|
||||||
|
if( pr:next( 1, 4) == 1 ) then
|
||||||
|
table.insert( replacements, {'dryplants:reed_roof', 'cottages:roof_straw'});
|
||||||
|
table.insert( replacements, {'dryplants:reed_slab', 'cottages:roof_flat_straw' });
|
||||||
|
table.insert( replacements, {'dryplants:wetreed_roof', 'cottages:roof_reet' });
|
||||||
|
table.insert( replacements, {'dryplants:wetreed_slab', 'cottages:roof_flat_reet' });
|
||||||
|
else -- replace the straw and cobble one of the huts uses
|
||||||
|
table.insert( replacements, {'cottages:straw', 'dryplants:wetreed' });
|
||||||
|
table.insert( replacements, {'stairs:slab_cobble', 'dryplants:reed_slab' });
|
||||||
|
end
|
||||||
|
if( pr:next( 1, 4) == 1 ) then
|
||||||
|
table.insert( replacements, {'dryplants:wetreed_roof_corner', 'default:wood' });
|
||||||
|
table.insert( replacements, {'dryplants:wetreed_roof_corner_2', 'default:junglewood' });
|
||||||
|
end
|
||||||
|
if( not( minetest.get_modpath( 'cavestuff' ))) then
|
||||||
|
table.insert( replacements, {'cavestuff:desert_pebble_2', 'default:slab_cobble' });
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert( replacements, {'default:desert_sand', 'default:dirt_with_grass' });
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_claytrader = function( housetype, pr, replacements )
|
||||||
|
-- the walls of the clay trader houses are made out of brick
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{ 'stairs:stair_brick', 'stairs:slab_brick', 'default:brick' }, -- default_materials
|
||||||
|
{ 'stairs:stair_', 'stairs:slab_', 'default:' }, -- prefixes (for new materials)
|
||||||
|
{ 'brick', 'stone', 'sandstone', 'sandstonebrick', 'desert_stone', 'desert_cobble', 'desert_stonebrick' }, -- new materials
|
||||||
|
'brick' ); -- original material
|
||||||
|
|
||||||
|
-- material for the floor
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:stone'},
|
||||||
|
{'default:'},
|
||||||
|
{ 'brick', 'stone', 'sandstone', 'sandstonebrick', 'clay', 'desert_stone', 'desert_cobble', 'desert_stonebrick',
|
||||||
|
'default:stone_flat', 'default:desert_stone_flat', -- realtest
|
||||||
|
},
|
||||||
|
'stone');
|
||||||
|
|
||||||
|
-- the clay trader homes come with stone stair roofs; slabs are used in other places as well (but those replacements here are ok)
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_stone', 'stairs:slab_stone' },
|
||||||
|
{'cottages:roof_connector_', 'cottages:roof_flat_' },
|
||||||
|
{'straw', 'straw', 'straw', 'straw', 'straw',
|
||||||
|
'reet', 'reet', 'reet',
|
||||||
|
'slate', 'slate',
|
||||||
|
'wood', 'wood',
|
||||||
|
'red',
|
||||||
|
'brown',
|
||||||
|
'black'},
|
||||||
|
'');
|
||||||
|
|
||||||
|
-- hills and pits that contain the materials clay traders dig for
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:stone_with_coal'},
|
||||||
|
{'default:'},
|
||||||
|
{'sand', 'sandstone', 'clay'},
|
||||||
|
'');
|
||||||
|
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
table.insert( replacements, {'default:clay', 'default:dirt_with_clay'});
|
||||||
|
local mfs2 = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_cobble', 'stairs:slab_cobble', 'default:cobble'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{ 'stone' }, -- will be replaced by mg_villages.realtest_stairs
|
||||||
|
'sandstone');
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_charachoal = function( housetype, pr, replacements )
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
|
||||||
|
table.insert( replacements, {'stairs:slab_loam', 'cottages:loam'});
|
||||||
|
table.insert( replacements, {'stairs:stair_loam', 'cottages:loam'});
|
||||||
|
end
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- wells can get the same replacements as the sourrounding village; they'll get a fitting roof that way
|
||||||
|
mg_villages.replacements_medieval = function( housetype, pr, replacements )
|
||||||
|
|
||||||
|
if( not( minetest.get_modpath('bell' ))) then
|
||||||
|
table.insert( replacements, {'bell:bell', 'default:goldblock' });
|
||||||
|
end
|
||||||
|
|
||||||
|
-- glass that served as a marker got copied accidently; there's usually no glass in cottages
|
||||||
|
table.insert( replacements, {'default:glass', 'air'});
|
||||||
|
-- some plants started growing while the buildings where saved - eliminate them
|
||||||
|
table.insert( replacements, {'junglegrass:medium', 'air'});
|
||||||
|
table.insert( replacements, {'junglegrass:short', 'air'});
|
||||||
|
table.insert( replacements, {'poisonivy:seedling', 'air'});
|
||||||
|
|
||||||
|
-- TODO: sometimes, half_door/half_door_inverted gets rotated wrong
|
||||||
|
-- table.insert( replacements, {'cottages:half_door', 'cottages:half_door_inverted'});
|
||||||
|
-- table.insert( replacements, {'cottages:half_door_inverted', 'cottages:half_door'});
|
||||||
|
|
||||||
|
-- some poor cottage owners cannot afford glass
|
||||||
|
if( pr:next( 1, 2 ) == 2 ) then
|
||||||
|
-- table.insert( replacements, {'cottages:glass_pane', 'default:fence_wood'});
|
||||||
|
local gp = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'cottages:glass_pane'},
|
||||||
|
{''},
|
||||||
|
{'xpanes:pane', 'default:glass', 'default:obsidian_glass', 'default:fence_wood',
|
||||||
|
'darkage:medieval_glass', 'darkage:iron_bars', 'darkage:iron_grille', 'darkage:wood_bars',
|
||||||
|
'darkage:wood_frame', 'darkage:wood_grille'},
|
||||||
|
'cottages:glass_pane');
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 'glass' is admittedly debatable; yet it may represent modernized old houses where only the tree-part was left standing
|
||||||
|
-- loam and clay are mentioned multiple times because those are the most likely building materials in reality
|
||||||
|
local materials = {'cottages:loam', 'cottages:loam', 'cottages:loam', 'cottages:loam', 'cottages:loam',
|
||||||
|
'default:clay', 'default:clay', 'default:clay', 'default:clay', 'default:clay',
|
||||||
|
'default:wood','default:junglewood', 'default:pine_wood', 'default:acacia_wood', 'default:sandstone',
|
||||||
|
'default:desert_stone','default:brick','default:cobble','default:stonebrick',
|
||||||
|
'default:desert_stonebrick','default:sandstonebrick','default:stone',
|
||||||
|
'mg:savannawood', 'mg:savannawood', 'mg:savannawood', 'mg:savannawood',
|
||||||
|
'mg:pinewood', 'mg:pinewood', 'mg:pinewood', 'mg:pinewood',
|
||||||
|
'default:stone_flat', 'default:desert_stone_flat', -- realtest
|
||||||
|
'darkage:adobe', 'darkage:basalt', 'darkage:basalt_cobble', 'darkage:chalk',
|
||||||
|
'darkage:gneiss', 'darkage:gneiss_cobble', 'darkage:marble', 'darkage:marble_tile',
|
||||||
|
'darkage:mud', 'darkage:ors', 'darkage:ors_cobble', 'darkage:reinforced_chalk',
|
||||||
|
'darkage:reinforced_wood', 'darkage:reinforced_wood_left', 'darkage:reinforced_wood_right',
|
||||||
|
'darkage:schist', 'darkage:serpentine', 'darkage:shale', 'darkage:silt', 'darkage:slate',
|
||||||
|
'darkage:slate_cobble', 'darkage:slate_tile', 'darkage:stone_brick',
|
||||||
|
'mapgen:mese_stone', 'mapgen:soap_stone'};
|
||||||
|
|
||||||
|
-- what is sandstone (the floor) may be turned into something else
|
||||||
|
local mfs = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:sandstone'},
|
||||||
|
{''},
|
||||||
|
materials,
|
||||||
|
'default:sandstone');
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
table.insert( replacements, {'stairs:slab_sandstone', 'default:stone_slab'});
|
||||||
|
local mfs2 = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_sandstone', 'stairs:slab_sandstone', 'default:sandstone'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{ 'stone' }, -- will be replaced by mg_villages.realtest_stairs
|
||||||
|
'sandstone');
|
||||||
|
elseif( mfs and mfs ~= 'default:sandstone' ) then
|
||||||
|
|
||||||
|
if( mfs == 'cottages:loam' or mfs == 'default:clay' or mfs == 'mg:savannawood' or mfs == 'mg:pinewood') then
|
||||||
|
mfs = 'default:wood';
|
||||||
|
elseif( mfs =='default:sandstonebrick' or mfs == 'default:desert_stone' or mfs == 'default:desert_stonebrick'
|
||||||
|
or not( minetest.registered_nodes[ 'stairs:slab_'..string.sub( mfs, 9 )] )) then
|
||||||
|
mfs = '';
|
||||||
|
end
|
||||||
|
|
||||||
|
if( mfs and mfs ~= '' ) then
|
||||||
|
-- realtest needs special treatment
|
||||||
|
table.insert( replacements, {'stairs:slab_sandstone', 'stairs:slab_'..string.sub( mfs, 9 )});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- except for the floor, everything else may be glass
|
||||||
|
table.insert( materials, 'default:glass' );
|
||||||
|
|
||||||
|
local uses_wood = false;
|
||||||
|
-- bottom part of the house (usually ground floor from outside)
|
||||||
|
local replace_clay = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:clay'},
|
||||||
|
{''},
|
||||||
|
materials,
|
||||||
|
'default:clay');
|
||||||
|
if( replace_clay and replace_clay ~= 'default:clay' ) then
|
||||||
|
uses_wood = mg_villages.replace_tree_trunk( replacements, replace_clay );
|
||||||
|
mg_villages.replace_saplings( replacements, replace_clay );
|
||||||
|
end
|
||||||
|
|
||||||
|
-- upper part of the house (may be the same as the material for the lower part)
|
||||||
|
local replace_loam = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'cottages:loam'},
|
||||||
|
{''},
|
||||||
|
materials,
|
||||||
|
'cottages:loam');
|
||||||
|
-- if the bottom was not replaced by wood, perhaps the top is
|
||||||
|
if( not( uses_wood ) and replace_loam ) then
|
||||||
|
mg_villages.replace_tree_trunk( replacements, replace_loam );
|
||||||
|
mg_villages.replace_saplings( replacements, replace_loam );
|
||||||
|
elseif( mg_villages.realtest_trees ) then
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- replace cobble; for these nodes, a stony material is needed (used in wells as well)
|
||||||
|
-- mossycobble is fine here as well
|
||||||
|
local mcs = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:cobble'},
|
||||||
|
{'default:'},
|
||||||
|
{'sandstone', 'desert_stone', 'desert_cobble',
|
||||||
|
'cobble', 'cobble',
|
||||||
|
'stonebrick', 'stonebrick', 'stonebrick', -- more common than other materials
|
||||||
|
'mossycobble', 'mossycobble','mossycobble',
|
||||||
|
'stone', 'stone',
|
||||||
|
'desert_stonebrick','sandstonebrick'},
|
||||||
|
'cobble');
|
||||||
|
-- set a fitting material for the slabs; mossycobble uses the default cobble slabs
|
||||||
|
if( mg_villages.realtest_trees ) then
|
||||||
|
local mcs2 = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_cobble', 'stairs:slab_cobble', 'default:cobble'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{ 'stone' }, -- will be replaced by mg_villages.realtest_stairs
|
||||||
|
'cobble');
|
||||||
|
table.insert( replacements, {'moreblocks:slab_cobble', 'default:'..mcs..'_slab'});
|
||||||
|
elseif( mcs ~= 'mossycobble' and mcs ~= 'cobble') then
|
||||||
|
|
||||||
|
-- if no slab exists, use sandstone slabs
|
||||||
|
if( not( mcs ) or not( minetest.registered_nodes[ 'stairs:slab_'..mcs ])) then
|
||||||
|
mcs = 'sandstone';
|
||||||
|
end
|
||||||
|
table.insert( replacements, {'stairs:slab_cobble', 'stairs:slab_'..mcs});
|
||||||
|
table.insert( replacements, {'moreblocks:slab_cobble', 'stairs:slab_'..mcs});
|
||||||
|
else
|
||||||
|
table.insert( replacements, {'moreblocks:slab_cobble', 'stairs:slab_'..mcs});
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- straw is the most likely building material for roofs for historical buildings
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
-- all three shapes of roof parts have to fit together
|
||||||
|
{ 'cottages:roof_straw', 'cottages:roof_connector_straw', 'cottages:roof_flat_straw' },
|
||||||
|
{ 'cottages:roof_', 'cottages:roof_connector_', 'cottages:roof_flat_'},
|
||||||
|
{'straw', 'straw', 'straw', 'straw', 'straw',
|
||||||
|
'reet', 'reet', 'reet',
|
||||||
|
'slate', 'slate',
|
||||||
|
'wood', 'wood',
|
||||||
|
'red',
|
||||||
|
'brown',
|
||||||
|
'black'},
|
||||||
|
'straw');
|
||||||
|
|
||||||
|
--print('REPLACEMENTS used: '..minetest.serialize( replacements ));
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mg_villages.replacements_tower = function( housetype, pr, replacements )
|
||||||
|
-- replace the wood - this is needed in particular for the fences
|
||||||
|
local wood_type = mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'default:wood'},
|
||||||
|
{''},
|
||||||
|
{ 'default:wood', 'default:junglewood', 'mg:savannawood', 'mg:pinewood' },
|
||||||
|
'default:wood');
|
||||||
|
mg_villages.replace_tree_trunk( replacements, wood_type );
|
||||||
|
mg_villages.replace_saplings( replacements, wood_type );
|
||||||
|
|
||||||
|
mg_villages.replace_materials( replacements, pr,
|
||||||
|
{'stairs:stair_cobble', 'stairs:slab_cobble', 'default:cobble'},
|
||||||
|
{'stairs:stair_', 'stairs:slab_', 'default:' },
|
||||||
|
{'stonebrick', 'desert_stonebrick','sandstonebrick', 'sandstone','stone','desert_stone','stone_flat','desert_stone_flat','stone_bricks','desert_strone_bricks'},
|
||||||
|
'stonebrick');
|
||||||
|
|
||||||
|
return replacements;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Translate replacement function from above (which aims at place_schematic) for the villages in Nores mapgen
|
||||||
|
mg_villages.get_replacement_ids = function( housetype, pr )
|
||||||
|
|
||||||
|
local replace = {};
|
||||||
|
local replacements = mg_villages.get_replacement_list( housetype, pr );
|
||||||
|
for i,v in ipairs( replacements ) do
|
||||||
|
if( v and #v == 2 ) then
|
||||||
|
replace[ minetest.get_content_id( v[1] )] = minetest.get_content_id( v[2] );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return replace;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- mapgen based replacements work best using a table, while minetest.place_schematic(..) based spawning needs a list
|
||||||
|
mg_villages.get_replacement_table = function( housetype, pr, replacements )
|
||||||
|
|
||||||
|
local rtable = {};
|
||||||
|
local ids = {};
|
||||||
|
if( not( replacements )) then
|
||||||
|
replacements = mg_villages.get_replacement_list( housetype, pr );
|
||||||
|
end
|
||||||
|
-- it is very problematic if the torches on houses melt snow and cause flooding; thus, we use a torch that is not hot
|
||||||
|
table.insert( replacements, {'default:torch', 'mg_villages:torch'});
|
||||||
|
|
||||||
|
-- make charachoal villages safe from spreading fire
|
||||||
|
if( not( mg_villages.use_normal_unsafe_lava )) then
|
||||||
|
table.insert( replacements, {'default:lava_source', 'mg_villages:lava_source_tamed'});
|
||||||
|
table.insert( replacements, {'default:lava_flowing', 'mg_villages:lava_flowing_tamed'});
|
||||||
|
end
|
||||||
|
|
||||||
|
for i,v in ipairs( replacements ) do
|
||||||
|
if( v and #v == 2 ) then
|
||||||
|
rtable[ v[1] ] = v[2];
|
||||||
|
ids[ minetest.get_content_id( v[1] )] = minetest.get_content_id( v[2] );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return { table = rtable, list = replacements, ids = ids };
|
||||||
|
end
|
||||||
|
|
||||||
|
mg_villages.get_content_id_replaced = function( node_name, replacements )
|
||||||
|
if( not( node_name ) or not( replacements ) or not(replacements.table )) then
|
||||||
|
return minetest.get_content_id( 'ignore' );
|
||||||
|
end
|
||||||
|
if( replacements.table[ node_name ]) then
|
||||||
|
return minetest.get_content_id( replacements.table[ node_name ] );
|
||||||
|
else
|
||||||
|
return minetest.get_content_id( node_name );
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- they don't all grow cotton; farming_plus fruits are far more intresting!
|
||||||
|
-- Note: This function modifies replacements.ids and replacements.table for each building
|
||||||
|
-- as far as fruits are concerned. It needs to be called before placing a building
|
||||||
|
-- which contains fruits.
|
||||||
|
-- The function might as well be a local one.
|
||||||
|
mg_villages.get_fruit_replacements = function( replacements, fruit)
|
||||||
|
|
||||||
|
if( not( fruit )) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=1,8 do
|
||||||
|
local old_name = '';
|
||||||
|
local new_name = '';
|
||||||
|
-- farming_plus plants sometimes come in 3 or 4 variants, but not in 8 as cotton does
|
||||||
|
if( minetest.registered_nodes[ 'farming_plus:'..fruit..'_'..i ]) then
|
||||||
|
old_name = "farming:cotton_"..i;
|
||||||
|
new_name = 'farming_plus:'..fruit..'_'..i;
|
||||||
|
|
||||||
|
-- "surplus" cotton variants will be replaced with the full grown fruit
|
||||||
|
elseif( minetest.registered_nodes[ 'farming_plus:'..fruit ]) then
|
||||||
|
old_name = "farming:cotton_"..i;
|
||||||
|
new_name = 'farming_plus:'..fruit;
|
||||||
|
|
||||||
|
-- and plants from farming: are supported as well
|
||||||
|
elseif( minetest.registered_nodes[ 'farming:'..fruit..'_'..i ]) then
|
||||||
|
old_name = "farming:cotton_"..i;
|
||||||
|
new_name = 'farming:'..fruit..'_'..i;
|
||||||
|
|
||||||
|
elseif( minetest.registered_nodes[ 'farming:'..fruit ]) then
|
||||||
|
old_name = "farming:cotton_"..i;
|
||||||
|
new_name = 'farming:'..fruit;
|
||||||
|
end
|
||||||
|
|
||||||
|
if( old_name ~= '' and new_name ~= '' ) then
|
||||||
|
-- this is mostly used by the voxelmanip based spawning of .we files
|
||||||
|
replacements.ids[ minetest.get_content_id( old_name )] = minetest.get_content_id( new_name );
|
||||||
|
-- this is used by the place_schematic based spawning
|
||||||
|
replacements.table[ old_name ] = new_name;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|