From d206b90ebcb1083d0b9f5fc7f83636463a5ab7ac Mon Sep 17 00:00:00 2001 From: Sokomine Date: Fri, 1 May 2015 20:08:05 +0200 Subject: [PATCH] moved handling of schematics into a seperate mod --- analyze_mts_file.lua | 273 -------- analyze_we_file.lua | 83 --- build_chest.lua | 932 ---------------------------- build_chest_add_schems.lua | 55 -- build_chest_handle_replacements.lua | 219 ------- build_chest_preview_image.lua | 215 ------- depends.txt | 1 + init.lua | 18 - place_buildings.lua | 808 ------------------------ replacements_farming.lua | 167 ----- replacements_realtest.lua | 82 --- replacements_roof.lua | 110 ---- replacements_wood.lua | 233 ------- rotate.lua | 114 ---- village_traders.lua | 146 ----- worldedit_file.lua | 138 ---- 16 files changed, 1 insertion(+), 3593 deletions(-) delete mode 100644 analyze_mts_file.lua delete mode 100644 analyze_we_file.lua delete mode 100644 build_chest.lua delete mode 100644 build_chest_add_schems.lua delete mode 100644 build_chest_handle_replacements.lua delete mode 100644 build_chest_preview_image.lua delete mode 100644 place_buildings.lua delete mode 100644 replacements_farming.lua delete mode 100644 replacements_realtest.lua delete mode 100644 replacements_roof.lua delete mode 100644 replacements_wood.lua delete mode 100644 rotate.lua delete mode 100644 village_traders.lua delete mode 100644 worldedit_file.lua diff --git a/analyze_mts_file.lua b/analyze_mts_file.lua deleted file mode 100644 index eb41ea5..0000000 --- a/analyze_mts_file.lua +++ /dev/null @@ -1,273 +0,0 @@ - ---[[ 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 = io.open(path..'.mts', "rb") - if (file == nil) then - return nil - end ---print('[mg_villages] Analyzing .mts file '..tostring( path..'.mts' )); ---if( not( string.byte )) then --- print( '[mg_villages] 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}; -- TODO: handle possible meta values contained in another file - 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 = io.open(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 ); - -- convert to .mts for later usage - if( res and store_as_mts ) then - handle_schematics.store_mts_file( store_as_mts, res ); - end - end - return res; -end diff --git a/analyze_we_file.lua b/analyze_we_file.lua deleted file mode 100644 index 3e7da65..0000000 --- a/analyze_we_file.lua +++ /dev/null @@ -1,83 +0,0 @@ -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 = io.open( scm..".we", "r") - if not f then - f, err = io.open( 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 - 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 - if ent.meta == nil then - ent.meta = {fields={}, inventory={}} - end - - scm[ent.y][ent.x][ent.z] = { nodenames_id[ ent.name ], ent.param2 }; --TODO ent.meta - - 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 }; -end diff --git a/build_chest.lua b/build_chest.lua deleted file mode 100644 index 8a1ce1a..0000000 --- a/build_chest.lua +++ /dev/null @@ -1,932 +0,0 @@ ------------------------------------------------------------------------------------------------------------------ --- 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"); - - - --- helper function; sorts by the second element of the table -local function build_chest_comp(a,b) - if (a[2] > b[2]) then - return true; - end -end - --- create a statistic about how frequent each node name occoured -build_chest.count_nodes = function( data ) - local statistic = {}; - -- 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, build_chest_comp ); - return statistic; -end - - - -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; - -- scm_data_cache is not stored as that would take up too much storage space - --build_chest.building[ building_name ].scm_data_cache = res.scm_data_cache; - - -- create a statistic about how often each node occours - build_chest.building[ building_name ].statistic = build_chest.count_nodes( res ); - - build_chest.building[ building_name ].preview = build_chest.preview_image_create_views( res, - build_chest.building[ building_name ].orients ); - return res; -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 - - - -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.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 ) )); - - - 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:]"; - - - if( building_name and building_name ~= '' and build_chest.building[ building_name ] and build_chest.building[ building_name ].size) then - local size = build_chest.building[ building_name ].size; - formspec = formspec.. - -- show which building has been selected - "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 - - 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 - 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 - - - -- 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 --- TODO: also show size and such - -- do replacements for realtest where necessary (this needs to be done only once) - local replacements = {}; - replacements_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 - --- 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.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 - -- /backup_PLAYERNAME_x_y_z_burried_rotation.mts - filename = minetest.get_worldpath()..'/backup_'.. - meta:get_string('owner')..'_'.. - tostring( start_pos.x )..':'..tostring( start_pos.y )..':'..tostring( start_pos.z )..'_'.. - '0_0.mts'; - --- TODO: handle metadata - -- store a backup of the original landscape - minetest.create_schematic( start_pos, end_pos, nil, filename, nil); - meta:set_string('backup', filename ); - - minetest.chat_send_player( pname, 'CREATING backup schematic for this place in '..tostring( filename )..'.'); - 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 ); - 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 - minetest.place_schematic( start_pos, backup_file, "0", {}, true ); - meta:set_string('backup', nil ); - 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: what if there is no schems folder in that directory? - -- TODO: forbid overwriting existing files? - local worldpath = minetest.get_worldpath(); - local filename_complete = worldpath..'/schems/'..filename..'.mts'; - -- really save it with probability_list and slice_prob_list both as nil - minetest.create_schematic( p1, p2, nil, filename_complete, nil); - - -- 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 - - meta:set_string( 'formspec', build_chest.update_formspec( pos, 'main', player, fields )); -end - - - -minetest.register_node("mg_villages:build", { --TODO - description = "Building-Spawner", - tiles = {"default_chest_side.png", "default_chest_top.png", "default_chest_side.png", - "default_chest_side.png", "default_chest_side.png", "default_chest_front.png"}, --- drawtype = 'signlike', --- paramtype = "light", --- paramtype2 = "wallmounted", --- sunlight_propagates = true, --- walkable = false, --- selection_box = { --- type = "wallmounted", --- }, - - paramtype2 = "facedir", - groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}, - legacy_facedir_simple = true, - after_place_node = function(pos, placer, itemstack) - - -- TODO: check if placement is allowed - - local meta = minetest.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 - 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, - -}) - - diff --git a/build_chest_add_schems.lua b/build_chest_add_schems.lua deleted file mode 100644 index 562bbec..0000000 --- a/build_chest_add_schems.lua +++ /dev/null @@ -1,55 +0,0 @@ - - -build_chest_add_to_menu = function( path, add_path ) - local file,error = 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 ); - 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_to_menu( minetest.get_modpath( minetest.get_current_modname()).."/list_of_schematics.txt", ""); diff --git a/build_chest_handle_replacements.lua b/build_chest_handle_replacements.lua deleted file mode 100644 index a10bb65..0000000 --- a/build_chest_handle_replacements.lua +++ /dev/null @@ -1,219 +0,0 @@ -------------------------------------------------------------- ---- 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]"; - 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 - - -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 - diff --git a/build_chest_preview_image.lua b/build_chest_preview_image.lua deleted file mode 100644 index cf0a16e..0000000 --- a/build_chest_preview_image.lua +++ /dev/null @@ -1,215 +0,0 @@ - - --- 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 mg_villages.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..mg_villages.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..mg_villages.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 diff --git a/depends.txt b/depends.txt index d81480b..9137f5e 100644 --- a/depends.txt +++ b/depends.txt @@ -1,3 +1,4 @@ +handle_schematics default doors farming diff --git a/init.lua b/init.lua index d75ec4d..861c91d 100644 --- a/init.lua +++ b/init.lua @@ -28,13 +28,6 @@ mg_villages.mg_generated_map = save_restore.restore_data( 'mg_generated_map.data dofile(mg_villages.modpath.."/config.lua") --- read size from schematics files directly --- analyze_mts_file.lua uses handle_schematics.* namespace -dofile(mg_villages.modpath.."/worldedit_file.lua") -- deserialize worldedit savefiles -dofile(mg_villages.modpath.."/analyze_mts_file.lua") -dofile(mg_villages.modpath.."/analyze_we_file.lua") -dofile(mg_villages.modpath.."/rotate.lua") - -- adds a special gravel node which will neither fall nor be griefed by mapgen dofile(mg_villages.modpath.."/nodes.lua") @@ -44,12 +37,6 @@ dofile(mg_villages.modpath.."/trees.lua") -- the replacement groups do add some non-ground nodes mg_villages.node_is_ground = {}; --- replace some materials for entire villages randomly -replacements_group = {}; -dofile(mg_villages.modpath.."/replacements_wood.lua") -dofile(mg_villages.modpath.."/replacements_realtest.lua") -dofile(mg_villages.modpath.."/replacements_farming.lua") -dofile(mg_villages.modpath.."/replacements_roof.lua") dofile(mg_villages.modpath.."/replacements.lua") -- multiple diffrent village types with their own sets of houses are supported @@ -57,9 +44,6 @@ dofile(mg_villages.modpath.."/replacements.lua") -- allows other mods to add new village types. dofile(mg_villages.modpath.."/village_types.lua") --- a chest for spawning buildings manually -dofile(mg_villages.modpath.."/build_chest.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") @@ -71,8 +55,6 @@ dofile(mg_villages.modpath.."/init_weights.lua") -- generate village names dofile(mg_villages.modpath.."/name_gen.lua"); -dofile(mg_villages.modpath.."/village_traders.lua") -dofile(mg_villages.modpath.."/place_buildings.lua") dofile(mg_villages.modpath.."/villages.lua") -- adds a command that allows to teleport to a known village diff --git a/place_buildings.lua b/place_buildings.lua deleted file mode 100644 index 5d9bbac..0000000 --- a/place_buildings.lua +++ /dev/null @@ -1,808 +0,0 @@ --- 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( data[ a:index(p.x, p.y, p.z)] == cid.c_snow and p.y1, 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) - - 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 ) then - mg_villages.get_fruit_replacements( replacements, pos.fruit); - end - - local traders = {}; - if( handle_schematics.choose_traders ) then - local village_type = ""; - if( village_id and mg_villages.all_villages and mg_villages.all_villages[ village_id ] ) then - village_type = mg_villages.all_villages[ village_id ].village_type; - end - local building_type = ""; - if( binfo.typ ) then - building_type = binfo.typ; - end - if( not( pos.traders )) then - traders = handle_schematics.choose_traders( village_type, building_type, replacements ) - end - 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(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 ) 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}); - - -- 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 - - -- determine suitable positions for the traders - if( handle_schematics.choose_trader_pos and #traders>0) then - extra_calls.traders = handle_schematics.choose_trader_pos(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, building_nr_in_bpos, village_id, binfo_extra, road_node, traders); - print('TRADERS CHOOSEN FOR '..tostring( binfo.scm )..': '..minetest.serialize( extra_calls.traders )); - 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 -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_private = handle_schematics.get_content_id_replaced( 'cottages:chest_private', replacements ); - cid.c_chest_work = handle_schematics.get_content_id_replaced( 'cottages:chest_work', replacements ); - cid.c_chest_storage = handle_schematics.get_content_id_replaced( 'cottages:chest_storage', 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 - generate_building(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, i, village_id, nil, mg_villages.road_node ) - 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 = mg_villages.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_private = handle_schematics.get_content_id_replaced( 'cottages:chest_private', replacements ); - cid.c_chest_work = handle_schematics.get_content_id_replaced( 'cottages:chest_work', replacements ); - cid.c_chest_storage = handle_schematics.get_content_id_replaced( 'cottages:chest_storage', 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 = {} }; - - generate_building(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, pos.building_nr, pos.village_id, binfo, cid.c_gravel); - - -- 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 - -- TODO: handle metadata (if any is provided) -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 ) then - param2 = 1; - 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; - end - end -end - - -if( minetest.get_modpath('moresnow' )) then - handle_schematics.moresnow_installed = true; -end diff --git a/replacements_farming.lua b/replacements_farming.lua deleted file mode 100644 index 6cd2015..0000000 --- a/replacements_farming.lua +++ /dev/null @@ -1,167 +0,0 @@ - -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) - if( mg_villages and mg_villages.node_is_ground ) then - for _,v in ipairs( data ) do - mg_villages.node_is_ground[ v ] = false; - end - end - - if( is_loaded 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" }, - "" - ); - - 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:', '_', '' ); - - -- 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(); diff --git a/replacements_realtest.lua b/replacements_realtest.lua deleted file mode 100644 index 0705707..0000000 --- a/replacements_realtest.lua +++ /dev/null @@ -1,82 +0,0 @@ -replacements_realtest = {} - --- parameter: replacements, name_in_default, name_in_realtest, to_realtest=true/false -replacements_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_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_realtest.stairs( repl, 'stone', 'stone', to_realtest ); - replacements_realtest.stairs( repl, 'cobble', 'stone_flat', to_realtest ); - replacements_realtest.stairs( repl, 'stonebrick', 'stone_bricks', to_realtest ); - replacements_realtest.stairs( repl, 'desert_stone', 'desert_stone', to_realtest ); - replacements_realtest.stairs( repl, 'desert_cobble', 'desert_stone_flat', to_realtest ); - replacements_realtest.stairs( repl, 'desert_stonebrick', 'desert_stone_bricks',to_realtest ); - replacements_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 - diff --git a/replacements_roof.lua b/replacements_roof.lua deleted file mode 100644 index 44e3215..0000000 --- a/replacements_roof.lua +++ /dev/null @@ -1,110 +0,0 @@ - -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(); diff --git a/replacements_wood.lua b/replacements_wood.lua deleted file mode 100644 index c813590..0000000 --- a/replacements_wood.lua +++ /dev/null @@ -1,233 +0,0 @@ -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 - if( mg_villages and mg_villages.node_is_ground ) then - for _,v in ipairs( data ) do - mg_villages.node_is_ground[ v ] = false; - end - end - - - if( is_loaded 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" }, - "" - ); - - 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(); - diff --git a/rotate.lua b/rotate.lua deleted file mode 100644 index 91d6abd..0000000 --- a/rotate.lua +++ /dev/null @@ -1,114 +0,0 @@ -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 diff --git a/village_traders.lua b/village_traders.lua deleted file mode 100644 index 8935c76..0000000 --- a/village_traders.lua +++ /dev/null @@ -1,146 +0,0 @@ - - -handle_schematics.choose_traders = function( village_type, building_type, replacements ) - - if( not( building_type ) or not( village_type )) then - return; - end - - -- some jobs are obvious - if( building_type == 'mill' ) then - return { 'miller' }; - elseif( building_type == 'bakery' ) then - return { 'baker' }; - elseif( building_type == 'school' ) then - return { 'teacher' }; - elseif( building_type == 'forge' ) then - local traders = {'blacksmith', 'bronzesmith' }; - return { traders[ math.random(#traders)] }; - elseif( building_type == 'shop' ) then - local traders = {'seeds','flowers','misc','default','ore', 'fruit trader', 'wood'}; - return { traders[ math.random(#traders)] }; - -- there are no traders for these jobs - they'd require specialized mobs - elseif( building_type == 'tower' - or building_type == 'church' - or building_type == 'secular' - or building_type == 'tavern' ) then - return {}; - end - - if( village_type == 'charachoal' ) then - return { 'charachoal' }; - elseif( village_type == 'claytrader' ) then - return { 'clay' }; - end - - local res = {}; - if( building_type == 'shed' - or building_type == 'farm_tiny' - or building_type == 'house' - or building_type == 'house_large' - or building_type=='hut') then - local traders = { 'stonemason', 'stoneminer', 'carpenter', 'toolmaker', - 'doormaker', 'furnituremaker', 'stairmaker', 'cooper', 'wheelwright', - 'saddler', 'roofer', 'iceman', 'potterer', 'bricklayer', 'dyemaker', - 'dyemakerl', 'glassmaker' } - -- sheds and farms both contain craftmen - res = { traders[ math.random( #traders )] }; - if( building_type == 'shed' - or building_type == 'house' - or building_type == 'house_large' - or building_type == 'hut' ) then - return res; - end - end - - if( building_type == 'field' - or building_type == 'farm_full' - or building_type == 'farm_tiny' ) then - - local fruit = 'farming:cotton'; - if( 'farm_full' ) then - -- RealTest - fruit = 'farming:wheat'; - if( replacements_group['farming'].traders[ 'farming:soy']) then - fruit_item = 'farming:soy'; - end - if( minetest.get_modpath("mobf") ) then - local animal_trader = {'animal_cow', 'animal_sheep', 'animal_chicken', 'animal_exotic'}; - res[1] = animal_trader[ math.random( #animal_trader )]; - end - return { res[1], replacements_group['farming'].traders[ fruit_item ]}; - elseif( #replacements_group['farming'].found > 0 ) then - -- get a random fruit to grow - fruit = replacements_group['farming'].found[ math.random( #replacements_group['farming'].found) ]; - return { res[1], replacements_group['farming'].traders[ fruit_item ]}; - else - return res; - end - end - - if( building_type == 'pasture' and minetest.get_modpath("mobf")) then - local animal_trader = {'animal_cow', 'animal_sheep', 'animal_chicken', 'animal_exotic'}; - return { animal_trader[ math.random( #animal_trader )] }; - end - - - -- TODO: banana,cocoa,rubber from farming_plus? - -- TODO: sawmill - if( building_type == 'lumberjack' or village_type == 'lumberjack' ) then - -- TODO: limit this to single houses - if( replacements.table and replacements.table[ 'default:wood' ] ) then - return { replacements_group['wood'].traders[ replacements.table[ 'default:wood' ]] }; - elseif( #replacements_group['wood'].traders > 0 ) then - return { replacements_group['wood'].traders[ math.random( #replacements_group['wood'].traders) ]}; - else - return { 'common_wood'}; - end - end - - - -- tent, chateau: places for living at; no special jobs associated - -- nore,taoki,medieval,lumberjack,logcabin,canadian,grasshut,tent: further village types - - return res; -end - - -handle_schematics.choose_trader_pos = function(pos, minp, maxp, data, param2_data, a, extranodes, replacements, cid, extra_calls, building_nr_in_bpos, village_id, binfo_extra, road_node, traders) - - local trader_pos = {}; - -- determine spawn positions for the mobs - for i,tr in ipairs( traders ) do - local tries = 0; - local found = false; - local pt = {x=pos.x, y=pos.y, z=pos.z}; - while( tries < 10 and not(found)) do - -- get a random position for the trader - pt.x = pos.x+math.random(pos.bsizex); - pt.z = pos.z+math.random(pos.bsizez); - -- check if it is inside the area contained in data - if (pt.x >= minp.x and pt.x <= maxp.x) and (pt.y >= minp.y and pt.y <= maxp.y) and (pt.z >= minp.z and pt.z <= maxp.z) then - - while( pt.y < maxp.y - and (data[ a:index( pt.x, pt.y, pt.z)]~=cid.c_air - or data[ a:index( pt.x, pt.y+1, pt.z)]~=cid.c_air )) do - pt.y = pt.y + 1; - end - - -- TODO: check if this position is really suitable? traders standing on the roof are a bit odd - found = true; - end - tries = tries+1; - - -- check if this position has already been assigned to another trader - for j,t in ipairs( trader_pos ) do - if( t.x==pt.x and t.y==pt.y and t.z==pt.z ) then - found = false; - end - end - end - if( found ) then - table.insert( trader_pos, {x=pt.x, y=pt.y, z=pt.z, typ=tr, bpos_i = building_nr_in_bpos} ); - end - end - return trader_pos; -end diff --git a/worldedit_file.lua b/worldedit_file.lua deleted file mode 100644 index 9f421dd..0000000 --- a/worldedit_file.lua +++ /dev/null @@ -1,138 +0,0 @@ ------------------------------------------------------------------------------------------- --- 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: - 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: ,,...: ---]] - - ---- 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